Compare commits
2062 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93c10fd77d | ||
|
|
14e8cc511a | ||
|
|
7674bd1926 | ||
|
|
be351f3118 | ||
|
|
47aa0b05b6 | ||
|
|
6d32cc9c4e | ||
|
|
fd9f4575eb | ||
|
|
c62fd2b58a | ||
|
|
712db598f7 | ||
|
|
0cccc30c98 | ||
|
|
19e6ebe9c4 | ||
|
|
24ed5413b2 | ||
|
|
a239c127bd | ||
|
|
61daec6597 | ||
|
|
544db75eb4 | ||
|
|
6a60eff5cd | ||
|
|
63aa04241c | ||
|
|
7a7550388d | ||
|
|
f2845b6632 | ||
|
|
deaeab3cbb | ||
|
|
16c9a0f974 | ||
|
|
18000b1b2c | ||
|
|
f1b56028b7 | ||
|
|
3d2315f754 | ||
|
|
07c898581c | ||
|
|
6612eeb9e3 | ||
|
|
04064ebf68 | ||
|
|
3de3c52c01 | ||
|
|
93929c73ee | ||
|
|
d68bede374 | ||
|
|
b659b27f95 | ||
|
|
70d0772e04 | ||
|
|
0a361bfb3b | ||
|
|
f9f47458d5 | ||
|
|
218dd439b6 | ||
|
|
7f3293609b | ||
|
|
356b7d8e64 | ||
|
|
d26c291a2a | ||
|
|
82d34eea7b | ||
|
|
4b0b0aa989 | ||
|
|
975d0dff25 | ||
|
|
b75410abc6 | ||
|
|
c0f5b53aaf | ||
|
|
ba285925ca | ||
|
|
a0dd2c66e4 | ||
|
|
64a9d557a4 | ||
|
|
3a5e5d4aaa | ||
|
|
f59c6c356e | ||
|
|
65b6e6d540 | ||
|
|
0d2e933ed1 | ||
|
|
b16fbb3040 | ||
|
|
638fc2881c | ||
|
|
2656cfd3ad | ||
|
|
80c5829792 | ||
|
|
957a850adc | ||
|
|
2a5e425b71 | ||
|
|
904ffb1417 | ||
|
|
777fec9a92 | ||
|
|
a2017c003e | ||
|
|
95842225fb | ||
|
|
7cfb175a45 | ||
|
|
b7165e0124 | ||
|
|
7132b06d6a | ||
|
|
4f79b8692c | ||
|
|
a8e307bb6a | ||
|
|
a30aca4759 | ||
|
|
4c0220d10a | ||
|
|
5fede2551e | ||
|
|
e83b521ee0 | ||
|
|
8da2b9cd94 | ||
|
|
dfcf715291 | ||
|
|
24c89b8ca3 | ||
|
|
b106e94494 | ||
|
|
28222b1832 | ||
|
|
c818dabe92 | ||
|
|
60f4a57425 | ||
|
|
a9ea686577 | ||
|
|
756f7cf6af | ||
|
|
ef9ef63f02 | ||
|
|
722035913e | ||
|
|
50aa2dcc2b | ||
|
|
b6cbebcc8a | ||
|
|
ba127c57d8 | ||
|
|
ef261455a2 | ||
|
|
1b1ab2e833 | ||
|
|
fbf7fa51e5 | ||
|
|
b0d2da04ac | ||
|
|
0ab16c9ebf | ||
|
|
d930ee205f | ||
|
|
0e330b81db | ||
|
|
6931538ebf | ||
|
|
b166396ef3 | ||
|
|
026c2677f9 | ||
|
|
34e2e01992 | ||
|
|
7b2d8ac1a2 | ||
|
|
256cc7d15c | ||
|
|
1d9b8f464a | ||
|
|
a8d1bf7e73 | ||
|
|
c58207dd2f | ||
|
|
1720ddc808 | ||
|
|
056d8817b2 | ||
|
|
e12f27a945 | ||
|
|
39fd89cb90 | ||
|
|
756215544a | ||
|
|
0768298b95 | ||
|
|
525ebbb9b7 | ||
|
|
c47ec3e70a | ||
|
|
20394271c7 | ||
|
|
731f670a2b | ||
|
|
d35c8e5b93 | ||
|
|
b1161d3542 | ||
|
|
47a01fc659 | ||
|
|
d72694ce06 | ||
|
|
85af736bfd | ||
|
|
b50da3eba4 | ||
|
|
4479daeaf1 | ||
|
|
a123de06c6 | ||
|
|
62f2aee00c | ||
|
|
b59cc4d038 | ||
|
|
3468737e14 | ||
|
|
5292e53b4a | ||
|
|
bae3fcfaba | ||
|
|
e4a57aa768 | ||
|
|
25451d361c | ||
|
|
daaacf4663 | ||
|
|
3cb0f60900 | ||
|
|
f2e28d18bc | ||
|
|
6cb54b9f9f | ||
|
|
ce3db115a3 | ||
|
|
dae4943593 | ||
|
|
ca8aa40034 | ||
|
|
a239374c4b | ||
|
|
1c833a28dc | ||
|
|
c30de78bf1 | ||
|
|
19b3adeb96 | ||
|
|
4b55150515 | ||
|
|
5bcfd5dd25 | ||
|
|
722f93b090 | ||
|
|
1ef50333a6 | ||
|
|
fa6ac4df41 | ||
|
|
517a8baea2 | ||
|
|
5473a6f8ac | ||
|
|
4d4dd6b249 | ||
|
|
2e6408a4f7 | ||
|
|
3c984ac8cf | ||
|
|
e52ea2a255 | ||
|
|
cf22b183a5 | ||
|
|
11d4151a82 | ||
|
|
c5f9e43d10 | ||
|
|
3329bc7d76 | ||
|
|
4c8ada2b80 | ||
|
|
6b446eb693 | ||
|
|
1663fa3ef1 | ||
|
|
7da0df2178 | ||
|
|
254c442a69 | ||
|
|
0568c47a37 | ||
|
|
c9c6c2ad12 | ||
|
|
f8ce2f1705 | ||
|
|
f9c35edd7c | ||
|
|
4cd490d871 | ||
|
|
936521981b | ||
|
|
fa96cdfaea | ||
|
|
2c13942ed5 | ||
|
|
af8a7d5093 | ||
|
|
04eb97ef93 | ||
|
|
0b49dcaa2d | ||
|
|
c3008b4179 | ||
|
|
28a29d219e | ||
|
|
0919d5d3de | ||
|
|
167e0d73d1 | ||
|
|
d87560b73e | ||
|
|
e6607fef6e | ||
|
|
f815b2b699 | ||
|
|
247c0ae46a | ||
|
|
f62d22f94a | ||
|
|
78a9cb35a3 | ||
|
|
e72b001d02 | ||
|
|
5bdbb9f13f | ||
|
|
0e7ab1cab8 | ||
|
|
f11de5bfc2 | ||
|
|
6d68f7f008 | ||
|
|
2bed827eb6 | ||
|
|
98cfef3306 | ||
|
|
f44839137c | ||
|
|
0decbdc2fb | ||
|
|
23b5ceb6c9 | ||
|
|
4b36beec40 | ||
|
|
b60ca9f6fa | ||
|
|
718c24ee47 | ||
|
|
86dd2886d2 | ||
|
|
23fb4651be | ||
|
|
877c9ca41a | ||
|
|
99fb775e30 | ||
|
|
1bb764a2d2 | ||
|
|
a3eab902ff | ||
|
|
e9684cd1a1 | ||
|
|
9ae0afaaf7 | ||
|
|
48bb5a3e9f | ||
|
|
f642513587 | ||
|
|
255623bbfd | ||
|
|
4270b12cd1 | ||
|
|
e3e6a22172 | ||
|
|
eb30c654c5 | ||
|
|
3b925c24ad | ||
|
|
beefdabc64 | ||
|
|
91e06cadf3 | ||
|
|
4ea5eb8292 | ||
|
|
af06f8e70a | ||
|
|
3238e295ba | ||
|
|
26fbd5c144 | ||
|
|
e64a2b98c4 | ||
|
|
42417e5554 | ||
|
|
82e613206e | ||
|
|
f1038152e9 | ||
|
|
2597a8faed | ||
|
|
8008ec895a | ||
|
|
d85d25b931 | ||
|
|
de62552ad1 | ||
|
|
155485173b | ||
|
|
82079fcf70 | ||
|
|
3b2eea5292 | ||
|
|
1f2ad9c177 | ||
|
|
cc6e5a6c69 | ||
|
|
c77c7a247a | ||
|
|
552440f50e | ||
|
|
2a9ccd7480 | ||
|
|
f265c055a5 | ||
|
|
837e5388ea | ||
|
|
9883dc6925 | ||
|
|
e3ad00e930 | ||
|
|
6428ae8b3a | ||
|
|
07c182d5b8 | ||
|
|
64aa15842c | ||
|
|
19c8da06e6 | ||
|
|
7dd959f4a1 | ||
|
|
148ae530d8 | ||
|
|
e75698ee9a | ||
|
|
80bea31b98 | ||
|
|
4ea57d1181 | ||
|
|
854847ca8a | ||
|
|
bd39e7cb0d | ||
|
|
20ef621a20 | ||
|
|
145c276c97 | ||
|
|
1c5d0dceb1 | ||
|
|
359f320b06 | ||
|
|
108d522dcf | ||
|
|
96e746c508 | ||
|
|
b2c862e7d5 | ||
|
|
9334fe9f24 | ||
|
|
b964385024 | ||
|
|
3f3059c98b | ||
|
|
8da616491d | ||
|
|
cb0db8750f | ||
|
|
08224443e3 | ||
|
|
5c2989196f | ||
|
|
4c4c84e104 | ||
|
|
232399ea28 | ||
|
|
9d22e4ec07 | ||
|
|
ee5bc16e47 | ||
|
|
74f0f885b9 | ||
|
|
b914d9aaba | ||
|
|
136f150d67 | ||
|
|
5b50cbb61b | ||
|
|
cb3a9bf195 | ||
|
|
cb847951e6 | ||
|
|
11228f0634 | ||
|
|
a0889d60f1 | ||
|
|
0055ebe8a7 | ||
|
|
58c7a9b9cc | ||
|
|
6afc081ff0 | ||
|
|
2c0ad2fc88 | ||
|
|
77e934beab | ||
|
|
368022ec43 | ||
|
|
69f8ca95bc | ||
|
|
dde8661e93 | ||
|
|
2604e1a0ff | ||
|
|
e8471bcc66 | ||
|
|
d230dd7365 | ||
|
|
74dce24e91 | ||
|
|
bc667a6474 | ||
|
|
a2cae06582 | ||
|
|
5212587055 | ||
|
|
efd42bc68f | ||
|
|
ebaa2e7918 | ||
|
|
7ebcc73a49 | ||
|
|
be09011bb7 | ||
|
|
2778a55e8e | ||
|
|
9b5fe3bfd6 | ||
|
|
91eef0d695 | ||
|
|
88704efad8 | ||
|
|
f4e4483392 | ||
|
|
63102bce23 | ||
|
|
8890a3dd0f | ||
|
|
3d9dec2c27 | ||
|
|
c96ad61c80 | ||
|
|
acd74d5b54 | ||
|
|
4808188964 | ||
|
|
1bb045b3b0 | ||
|
|
bdca60c0ad | ||
|
|
8d9c135498 | ||
|
|
0f76482916 | ||
|
|
38eb86bdee | ||
|
|
cbce9892d5 | ||
|
|
f624b7a331 | ||
|
|
1ebcd61a75 | ||
|
|
358da72ffe | ||
|
|
9666feca37 | ||
|
|
03eb52eac8 | ||
|
|
6562cc710c | ||
|
|
222001bc13 | ||
|
|
e93f14248a | ||
|
|
7119f1bc81 | ||
|
|
548fa3f6ee | ||
|
|
8ddd309d5d | ||
|
|
8c8acbb546 | ||
|
|
fe30f27af3 | ||
|
|
d5d2eaba8a | ||
|
|
e8f64bfe8f | ||
|
|
79b03993b0 | ||
|
|
e3b8f9cb8c | ||
|
|
819463a865 | ||
|
|
c69777ca39 | ||
|
|
40f3e828aa | ||
|
|
dc8520ebec | ||
|
|
7ffbedf0dd | ||
|
|
826fad1ad4 | ||
|
|
1c4d3aebad | ||
|
|
ff6e93fc15 | ||
|
|
17e88bb97d | ||
|
|
d3dd26c596 | ||
|
|
c2a7509e0e | ||
|
|
079040b721 | ||
|
|
b80d239820 | ||
|
|
c3ff43dac2 | ||
|
|
4ac51afd8f | ||
|
|
26eab51698 | ||
|
|
388dcf2a1f | ||
|
|
9bfd14d067 | ||
|
|
061e0562d1 | ||
|
|
2ba20b013d | ||
|
|
dc36f87a6e | ||
|
|
e82ecb48b8 | ||
|
|
c56a134179 | ||
|
|
11028456ad | ||
|
|
81fcb02974 | ||
|
|
5ef4976c53 | ||
|
|
160356072f | ||
|
|
c10df5b634 | ||
|
|
70fdd5b0b3 | ||
|
|
6c1ec51fab | ||
|
|
66b1c22174 | ||
|
|
97138fd6b9 | ||
|
|
03c69be421 | ||
|
|
3a9a952cb0 | ||
|
|
3bd0331aa3 | ||
|
|
3ecf224d91 | ||
|
|
37743606a2 | ||
|
|
58587f4a9a | ||
|
|
464fde1851 | ||
|
|
2639498642 | ||
|
|
49f074737c | ||
|
|
3d53a8b434 | ||
|
|
e260433c7a | ||
|
|
88ef8bff0b | ||
|
|
fbdac36f6f | ||
|
|
da3876bd83 | ||
|
|
d303e700ae | ||
|
|
92a1173b9e | ||
|
|
9f7ebb1ac7 | ||
|
|
1a8690e1f2 | ||
|
|
6543e4c5da | ||
|
|
dd904fe3c2 | ||
|
|
c14cc6bf0b | ||
|
|
95c265ffd3 | ||
|
|
31c1ae68df | ||
|
|
f2eb0c3b6b | ||
|
|
32be33847c | ||
|
|
3100b0c044 | ||
|
|
f4ec3ab379 | ||
|
|
cdd7faa9bb | ||
|
|
e7b35aeaf7 | ||
|
|
696256eb5b | ||
|
|
8ad560ce0e | ||
|
|
1c71506f62 | ||
|
|
8bea6ec5b0 | ||
|
|
e8144487ee | ||
|
|
41d9d15dda | ||
|
|
124b97c024 | ||
|
|
98e0b45403 | ||
|
|
1f2b8d8bf6 | ||
|
|
8327751b91 | ||
|
|
6417f89596 | ||
|
|
2e53656f44 | ||
|
|
822cf0ad07 | ||
|
|
67f04a81b3 | ||
|
|
9232ad0125 | ||
|
|
0de87b3e1e | ||
|
|
74b8cd6156 | ||
|
|
ac959387fe | ||
|
|
ffd8ce9281 | ||
|
|
d8052b295f | ||
|
|
625929133c | ||
|
|
79c28e7e1d | ||
|
|
01f4a79f07 | ||
|
|
47c5a2215e | ||
|
|
bb6e38630f | ||
|
|
85acf69d4f | ||
|
|
69ba56ebef | ||
|
|
527a61f909 | ||
|
|
a15ebcde24 | ||
|
|
e80629cc40 | ||
|
|
d956ae9726 | ||
|
|
0435d6d7b9 | ||
|
|
59752e6fe9 | ||
|
|
d3ee0bfdf4 | ||
|
|
463df825f0 | ||
|
|
480559ef0b | ||
|
|
2a4fd346f9 | ||
|
|
6200fed224 | ||
|
|
e1b4585dc7 | ||
|
|
c5eb72fa9f | ||
|
|
d2e19ef4c3 | ||
|
|
4509c43b81 | ||
|
|
e2ffe716e7 | ||
|
|
0d9ededea9 | ||
|
|
2edc4369d2 | ||
|
|
32baa95500 | ||
|
|
ad9f3ce078 | ||
|
|
c1f66b1885 | ||
|
|
e0be15cf01 | ||
|
|
93660bfc81 | ||
|
|
6446942e73 | ||
|
|
0038cf8c4e | ||
|
|
7f177aef08 | ||
|
|
a7a42ea5ec | ||
|
|
14cddfd42f | ||
|
|
ae0ce65674 | ||
|
|
9c9926d5a7 | ||
|
|
95a3c41baa | ||
|
|
f2518baef9 | ||
|
|
4be9265546 | ||
|
|
9f9c46e370 | ||
|
|
5816d0bb12 | ||
|
|
70c2b99771 | ||
|
|
6177d4a2c4 | ||
|
|
05f012e590 | ||
|
|
cc0506490f | ||
|
|
06114c9835 | ||
|
|
2518e4d47d | ||
|
|
ceea805196 | ||
|
|
ae7e515945 | ||
|
|
b275f91a58 | ||
|
|
b8ef96028c | ||
|
|
6ba1fdb744 | ||
|
|
dcef38427b | ||
|
|
20d7ae7144 | ||
|
|
d576777d94 | ||
|
|
1f7344ca1b | ||
|
|
87c69f7456 | ||
|
|
a684b35203 | ||
|
|
37855fe836 | ||
|
|
f596695f61 | ||
|
|
076d065f7c | ||
|
|
70a7a7bbdd | ||
|
|
5f540a4c08 | ||
|
|
f33b30fe79 | ||
|
|
2f546f214d | ||
|
|
7ba4fda346 | ||
|
|
299415a889 | ||
|
|
718af984ab | ||
|
|
5d51657f32 | ||
|
|
a2958ba808 | ||
|
|
79c2130152 | ||
|
|
98d3cc2637 | ||
|
|
8339aa0934 | ||
|
|
5451c110b1 | ||
|
|
20595a11bc | ||
|
|
c92a1b516c | ||
|
|
a8f1a881ff | ||
|
|
ec21a55271 | ||
|
|
89990624ec | ||
|
|
6caf7f356b | ||
|
|
241a6c5818 | ||
|
|
57fb52e8f0 | ||
|
|
7b00385155 | ||
|
|
2b4aa1d6b2 | ||
|
|
4ba5113842 | ||
|
|
a36bf2df65 | ||
|
|
f5002cae36 | ||
|
|
cb8022c55d | ||
|
|
2a65e00988 | ||
|
|
05358cdfe4 | ||
|
|
7b43a94055 | ||
|
|
36e19e82e7 | ||
|
|
c52a802b83 | ||
|
|
b233600b8c | ||
|
|
93df859aa4 | ||
|
|
f1f79fb961 | ||
|
|
92fa75b6c2 | ||
|
|
1d5f3a0486 | ||
|
|
b89c200076 | ||
|
|
597a8cd6c8 | ||
|
|
e477449cd4 | ||
|
|
ea1e4541c0 | ||
|
|
50572ac40f | ||
|
|
fd81036909 | ||
|
|
0e27886e28 | ||
|
|
45bad3be04 | ||
|
|
30b268dc3a | ||
|
|
ef99f0ef36 | ||
|
|
e357ba0125 | ||
|
|
36b75a5928 | ||
|
|
64d3ea2804 | ||
|
|
0a93affeef | ||
|
|
402d13a322 | ||
|
|
adf0efc859 | ||
|
|
d1c65fd273 | ||
|
|
8a27c6a52f | ||
|
|
d7cc52bc99 | ||
|
|
f0f5300891 | ||
|
|
6e90e72b4a | ||
|
|
c655963483 | ||
|
|
9f2e4ac312 | ||
|
|
9e25366f85 | ||
|
|
c102d8731a | ||
|
|
0983ba1339 | ||
|
|
0a99eca7cd | ||
|
|
116bbec73e | ||
|
|
bf19540f8d | ||
|
|
dff3ae7410 | ||
|
|
76614bcde0 | ||
|
|
2953f9eefc | ||
|
|
4a24605361 | ||
|
|
decabe8d47 | ||
|
|
51adcf0f1e | ||
|
|
2a6a07fef6 | ||
|
|
315cf63118 | ||
|
|
e28d362aad | ||
|
|
e0d9b8f715 | ||
|
|
eff6b75c43 | ||
|
|
e8be0adf37 | ||
|
|
9f4a82bb62 | ||
|
|
8d7e14f21d | ||
|
|
d03d3622aa | ||
|
|
821c32992d | ||
|
|
b52cf9f3cd | ||
|
|
ab8e687f96 | ||
|
|
90703703aa | ||
|
|
176984afe0 | ||
|
|
542efa17ff | ||
|
|
6a2c2dbba1 | ||
|
|
426de61525 | ||
|
|
24c8d06d41 | ||
|
|
227f5e5176 | ||
|
|
92e39a3e21 | ||
|
|
fb2300e2fa | ||
|
|
78becae5e9 | ||
|
|
d10eb4370e | ||
|
|
9c92ef941f | ||
|
|
7aefe3d71b | ||
|
|
398db964b8 | ||
|
|
579349b104 | ||
|
|
5f9a83871d | ||
|
|
da0c5e67c5 | ||
|
|
a0cfde18c3 | ||
|
|
0ad4889936 | ||
|
|
36e809d530 | ||
|
|
78096658e2 | ||
|
|
3edd218e3a | ||
|
|
569bf6335b | ||
|
|
7b8919d706 | ||
|
|
147fd87d8c | ||
|
|
ac0926d40b | ||
|
|
105d472f5d | ||
|
|
c1a49da385 | ||
|
|
c3f596e64e | ||
|
|
adfda84c41 | ||
|
|
345cc118a3 | ||
|
|
df070ac0cf | ||
|
|
7b88be2635 | ||
|
|
c30a39d29a | ||
|
|
36db41a1f0 | ||
|
|
8b249dc06a | ||
|
|
0c6872b352 | ||
|
|
58944993b8 | ||
|
|
3cfffa5fbb | ||
|
|
4873b8b413 | ||
|
|
0b85f5192c | ||
|
|
3e9a1776a1 | ||
|
|
e1fbe9ae54 | ||
|
|
f48d1a8017 | ||
|
|
0debc90695 | ||
|
|
8d42ea7cfd | ||
|
|
1dae80a633 | ||
|
|
d398c86b0c | ||
|
|
70809e0647 | ||
|
|
4c1a5168f0 | ||
|
|
f9acfbc224 | ||
|
|
5f78e1a983 | ||
|
|
7bc5579fb7 | ||
|
|
57750efcb2 | ||
|
|
a33ee1cda9 | ||
|
|
cd20a0679a | ||
|
|
20e546e02b | ||
|
|
f5547f093e | ||
|
|
c00d95242d | ||
|
|
05c4d23df6 | ||
|
|
06fa17f33f | ||
|
|
194285289c | ||
|
|
a61fa61330 | ||
|
|
68c922ee12 | ||
|
|
d1042b276b | ||
|
|
9bbffe150f | ||
|
|
b95be526d3 | ||
|
|
165f9d769b | ||
|
|
a0ea75b74e | ||
|
|
4075f92eec | ||
|
|
035aff5454 | ||
|
|
52dc7ad259 | ||
|
|
c3c83f608c | ||
|
|
ffba351a16 | ||
|
|
a12623e142 | ||
|
|
1a691a103e | ||
|
|
5e725e0bbe | ||
|
|
93c2fa4c73 | ||
|
|
f412fb21d6 | ||
|
|
bd4b6c1f01 | ||
|
|
d1839d87e7 | ||
|
|
1fc163eb5f | ||
|
|
cd2b3cb73e | ||
|
|
88b5cf2461 | ||
|
|
2ccb0af75e | ||
|
|
27ee6e7643 | ||
|
|
a3207a5703 | ||
|
|
72ff64a7f8 | ||
|
|
9c06d1d0ae | ||
|
|
f11afd4414 | ||
|
|
2aa70b6ab8 | ||
|
|
4626a6f609 | ||
|
|
9152f8559f | ||
|
|
7f4c61b15a | ||
|
|
b365131363 | ||
|
|
a6ea4dd0d7 | ||
|
|
9c6649f077 | ||
|
|
04ba202e12 | ||
|
|
352a6c5691 | ||
|
|
72bccad82d | ||
|
|
6d52a2b409 | ||
|
|
9b1035a5f2 | ||
|
|
ce7c3e8039 | ||
|
|
9baec288c3 | ||
|
|
82894b94f4 | ||
|
|
fb00d68aa7 | ||
|
|
12288a2622 | ||
|
|
f84ce3f1d1 | ||
|
|
306b3f72d8 | ||
|
|
593a04d047 | ||
|
|
667548f3ed | ||
|
|
8f89bf6402 | ||
|
|
ff28e7c86e | ||
|
|
67cc69179b | ||
|
|
06fac2b7a3 | ||
|
|
a354f6bdc5 | ||
|
|
cb44c71733 | ||
|
|
6b1c14f875 | ||
|
|
7770aba877 | ||
|
|
05381096aa | ||
|
|
6bdd9ad4dd | ||
|
|
19836e8898 | ||
|
|
5e4b193260 | ||
|
|
923d0f2b7a | ||
|
|
56f1a93c4e | ||
|
|
0168182af5 | ||
|
|
679f0e1cd8 | ||
|
|
dd6b9bb38d | ||
|
|
5bd8f35dc0 | ||
|
|
53fc939e35 | ||
|
|
42d6c79710 | ||
|
|
882869255b | ||
|
|
19903751c1 | ||
|
|
836074fb60 | ||
|
|
5865a70c2e | ||
|
|
fa057ee9d3 | ||
|
|
2d88fcb249 | ||
|
|
920bb04b00 | ||
|
|
a915e62e2c | ||
|
|
226a6c50e0 | ||
|
|
269f13de76 | ||
|
|
3ee796a663 | ||
|
|
d24af2f4db | ||
|
|
f86c3cfd91 | ||
|
|
11061bdd07 | ||
|
|
f901f802bb | ||
|
|
a98c209101 | ||
|
|
6a459682ca | ||
|
|
1a7194b3a9 | ||
|
|
b6c9ef4a15 | ||
|
|
20e550bc7d | ||
|
|
a4b7766947 | ||
|
|
8d1a0071b6 | ||
|
|
a3c00e607b | ||
|
|
de7ca8b736 | ||
|
|
04e593dc62 | ||
|
|
2294c38aa9 | ||
|
|
6f41d39a9c | ||
|
|
7c4e33b676 | ||
|
|
4cc66bccad | ||
|
|
55b1d34f48 | ||
|
|
4da0e8d8ad | ||
|
|
b95bfba676 | ||
|
|
1ff2bfd390 | ||
|
|
a35fa5b158 | ||
|
|
22169bda0d | ||
|
|
faf5f6c69d | ||
|
|
1ae01d4078 | ||
|
|
eb6289dd1c | ||
|
|
671df6eafb | ||
|
|
579563b32c | ||
|
|
135b93a5af | ||
|
|
84c6e09c42 | ||
|
|
b4f9808d11 | ||
|
|
d96d4224a2 | ||
|
|
f65927e308 | ||
|
|
eeeea8566e | ||
|
|
54c42b276f | ||
|
|
8e4b4d6e41 | ||
|
|
ac9fd9070f | ||
|
|
6348649bc6 | ||
|
|
c95886d8db | ||
|
|
117b965a7b | ||
|
|
1b6b5f9afa | ||
|
|
83bc8d9e86 | ||
|
|
33f0421d3f | ||
|
|
661615e546 | ||
|
|
c52fc90306 | ||
|
|
eeb55fbc42 | ||
|
|
5d77eb1901 | ||
|
|
654a94fe3d | ||
|
|
4238708226 | ||
|
|
5f02072bf3 | ||
|
|
eec5b448b6 | ||
|
|
5cda756f92 | ||
|
|
e9588dd85b | ||
|
|
dda0e4aa06 | ||
|
|
2282406166 | ||
|
|
b3f0dee8e9 | ||
|
|
f9f7381247 | ||
|
|
48685325e6 | ||
|
|
e8bcaf415c | ||
|
|
c9197e8df7 | ||
|
|
2bb09cf575 | ||
|
|
7bf4ad3884 | ||
|
|
5154d7ac84 | ||
|
|
9299653722 | ||
|
|
b0f0133d29 | ||
|
|
9211b6f0c0 | ||
|
|
ab6a0ed6dd | ||
|
|
c975c1e4aa | ||
|
|
f9a593dc74 | ||
|
|
9151520d50 | ||
|
|
8f72d877bd | ||
|
|
e1990c9315 | ||
|
|
4cd5dcbfcf | ||
|
|
3ee2125e8f | ||
|
|
4652f3b449 | ||
|
|
697717eb1e | ||
|
|
cbde71f5f1 | ||
|
|
bf52afa21d | ||
|
|
2083e008ab | ||
|
|
2be0d23b1b | ||
|
|
fda56dda25 | ||
|
|
ed259781e9 | ||
|
|
0c7fcd5a7a | ||
|
|
310b7b9065 | ||
|
|
cd534bbda7 | ||
|
|
1a66eaf7bf | ||
|
|
a94d6e3dd8 | ||
|
|
54cfb2bbc4 | ||
|
|
00bc3f76cf | ||
|
|
71a6d378d9 | ||
|
|
99a5aee8b3 | ||
|
|
89d2a23dac | ||
|
|
ee1bf47f5c | ||
|
|
13ac20f8b3 | ||
|
|
adef05bbdf | ||
|
|
f03ff452b8 | ||
|
|
c39489060b | ||
|
|
002fa8f4aa | ||
|
|
d2c747258c | ||
|
|
53e3664726 | ||
|
|
26ff9f6b53 | ||
|
|
f542f1c854 | ||
|
|
33041ffa75 | ||
|
|
1493164df9 | ||
|
|
8ffef558ff | ||
|
|
8b3f44ffca | ||
|
|
2706529006 | ||
|
|
7e331a2055 | ||
|
|
505329730c | ||
|
|
1a07404c10 | ||
|
|
b02adc7758 | ||
|
|
952252ebcd | ||
|
|
eee0c40132 | ||
|
|
567bad33e1 | ||
|
|
b5c0e93989 | ||
|
|
ac17df2a86 | ||
|
|
a9a5899252 | ||
|
|
395d85c1b4 | ||
|
|
52ba1ce17f | ||
|
|
604a246fe8 | ||
|
|
e172c4871c | ||
|
|
2a9b32690d | ||
|
|
76fa4745d0 | ||
|
|
6f4d26e9d3 | ||
|
|
f40f43861d | ||
|
|
717ebbbb24 | ||
|
|
79c69e1b1e | ||
|
|
8fc95e08dc | ||
|
|
3f06528ba3 | ||
|
|
0e44b10eec | ||
|
|
d74fe92ce8 | ||
|
|
8037948f7f | ||
|
|
ab29170972 | ||
|
|
6f843e2499 | ||
|
|
6b8a816ce6 | ||
|
|
2c0541fb79 | ||
|
|
cb22890d79 | ||
|
|
5a9346cc80 | ||
|
|
1c85220ffa | ||
|
|
39d4818def | ||
|
|
db0cc66ba0 | ||
|
|
c10a64f08a | ||
|
|
5a3d60b203 | ||
|
|
28b9bf1f76 | ||
|
|
27dbb2dd9e | ||
|
|
9b7b790f21 | ||
|
|
e3666e5bf3 | ||
|
|
9e38cd8dc2 | ||
|
|
b105b9fd8f | ||
|
|
6a018f3e25 | ||
|
|
ab26d422e9 | ||
|
|
f4e18fb87c | ||
|
|
2b20ff4e67 | ||
|
|
28d5cd481b | ||
|
|
42f3340190 | ||
|
|
0ef50e1b6d | ||
|
|
01ddded603 | ||
|
|
fe7e0ffbba | ||
|
|
5df6066150 | ||
|
|
8393cdb2de | ||
|
|
da19272eb6 | ||
|
|
60fb83d770 | ||
|
|
1c90b03476 | ||
|
|
50502ce720 | ||
|
|
39f9d02454 | ||
|
|
ce627b0e18 | ||
|
|
cdb4980337 | ||
|
|
878148ac32 | ||
|
|
0bc29f0563 | ||
|
|
e201f71a74 | ||
|
|
7e684885cf | ||
|
|
e600c1b50c | ||
|
|
5da2faa400 | ||
|
|
05cd134a24 | ||
|
|
2f27a7d00b | ||
|
|
d61d4d0a74 | ||
|
|
4033cd61c2 | ||
|
|
7cd6f372e6 | ||
|
|
ffe6eb3de7 | ||
|
|
e2b0b1b1fb | ||
|
|
1f15ca70a3 | ||
|
|
904ee6a9b3 | ||
|
|
0461e98a4c | ||
|
|
dc01a18b87 | ||
|
|
7be0e284c2 | ||
|
|
6dd79d5b8f | ||
|
|
f81b725d42 | ||
|
|
cfeecd98f6 | ||
|
|
d054dd33e2 | ||
|
|
45ad84a9bc | ||
|
|
a333662f56 | ||
|
|
59f716563f | ||
|
|
6815f8c9b7 | ||
|
|
8e5360ac38 | ||
|
|
aa6809ad5f | ||
|
|
d8a7d427c3 | ||
|
|
bc1b45d912 | ||
|
|
50c5283599 | ||
|
|
02ef65bcfd | ||
|
|
904245bb21 | ||
|
|
57e29b2be9 | ||
|
|
53a5603f64 | ||
|
|
8805a21567 | ||
|
|
c6fee92450 | ||
|
|
46c90f3712 | ||
|
|
e3c1c6ee9a | ||
|
|
8bfbd69a2c | ||
|
|
6a6649823e | ||
|
|
bfb95d503a | ||
|
|
d1b4736ef9 | ||
|
|
e56e58b634 | ||
|
|
fed5b6b695 | ||
|
|
e96870cfbd | ||
|
|
acda7c13b2 | ||
|
|
7d5c7f8493 | ||
|
|
4ef3f3568d | ||
|
|
f81bd26649 | ||
|
|
2a407bfe47 | ||
|
|
f70f126f76 | ||
|
|
f06591fde8 | ||
|
|
e0c9a9dc17 | ||
|
|
0f16fc2776 | ||
|
|
7aa7cdf6f3 | ||
|
|
82a8a890de | ||
|
|
f8df901963 | ||
|
|
8b08d1d599 | ||
|
|
f3ddba3edc | ||
|
|
acbec6db7e | ||
|
|
d2390473bc | ||
|
|
e273d64be3 | ||
|
|
2a90256d32 | ||
|
|
560712db21 | ||
|
|
483b42d2b8 | ||
|
|
d1a6e53f5c | ||
|
|
f5a55abf58 | ||
|
|
0bc94b90d7 | ||
|
|
9ed4bd9366 | ||
|
|
d3352e476f | ||
|
|
4b4c5fc0ab | ||
|
|
38b9c7c38a | ||
|
|
c71ce41c83 | ||
|
|
4cd030215d | ||
|
|
2ce5d6f727 | ||
|
|
b55a0df8e1 | ||
|
|
ee5fa23a7a | ||
|
|
75ab6f25f4 | ||
|
|
eaed82c9b2 | ||
|
|
2a4be6fcd7 | ||
|
|
e6198500f7 | ||
|
|
7db36c83c1 | ||
|
|
0e1921698c | ||
|
|
95eed1ecec | ||
|
|
2e61235403 | ||
|
|
d6b53f78ab | ||
|
|
a2c7ff63df | ||
|
|
9fb15545bd | ||
|
|
277e08b94a | ||
|
|
46224fe9b8 | ||
|
|
56180ca419 | ||
|
|
dc65753a0b | ||
|
|
d8857d8e72 | ||
|
|
fdc3e0a5f5 | ||
|
|
8f7180eb6c | ||
|
|
8945602eae | ||
|
|
7826f77425 | ||
|
|
00372e85c5 | ||
|
|
a1ffc5c33b | ||
|
|
8a44a41abb | ||
|
|
23f0c56eba | ||
|
|
3d25863ccb | ||
|
|
bb6daca735 | ||
|
|
4bd993b1e3 | ||
|
|
f81816b0cd | ||
|
|
7ac605c038 | ||
|
|
2a8b67d11e | ||
|
|
16893cca24 | ||
|
|
94ab788032 | ||
|
|
e3a333564a | ||
|
|
13d6cf201f | ||
|
|
40ef3191fc | ||
|
|
bda2b91c92 | ||
|
|
1462bfa297 | ||
|
|
bafcb97fa1 | ||
|
|
f905676b1c | ||
|
|
0ea81b13b9 | ||
|
|
9a7949297e | ||
|
|
29342fa9ac | ||
|
|
bd4438d99b | ||
|
|
f8e14e8fd5 | ||
|
|
b2c66c9cda | ||
|
|
44e5c32bcb | ||
|
|
e7fc4e7f89 | ||
|
|
e589486907 | ||
|
|
459c4c5d86 | ||
|
|
73c56f038e | ||
|
|
0a4888f861 | ||
|
|
da27ca98b3 | ||
|
|
f1e1ccad28 | ||
|
|
7616c06ff9 | ||
|
|
0c1f4750ea | ||
|
|
0a26c295a0 | ||
|
|
32d23e0484 | ||
|
|
c028770f8e | ||
|
|
8f1a99b37e | ||
|
|
e66651a4cb | ||
|
|
1d9a052870 | ||
|
|
d3ee749c14 | ||
|
|
33076aa33a | ||
|
|
2a2663eeb5 | ||
|
|
fa04eb67db | ||
|
|
f8ad8a7211 | ||
|
|
5f4d6dffef | ||
|
|
b9c7510946 | ||
|
|
c0e709a0e3 | ||
|
|
e690be1bdd | ||
|
|
6ed5190276 | ||
|
|
4c4a351fbd | ||
|
|
435ffc75b6 | ||
|
|
4dbc06bdd0 | ||
|
|
5a7cbb2f3d | ||
|
|
354b55cbbc | ||
|
|
b87a950357 | ||
|
|
950c236720 | ||
|
|
32982be4f2 | ||
|
|
f467331934 | ||
|
|
ec839e6aae | ||
|
|
45f1521da6 | ||
|
|
841a44a18e | ||
|
|
1deacaecf9 | ||
|
|
6af8e6c25b | ||
|
|
b0849d21f3 | ||
|
|
5b60ea8e77 | ||
|
|
ec3f95a260 | ||
|
|
0bfd4d2e04 | ||
|
|
a6ba0cfc97 | ||
|
|
6d55eb5974 | ||
|
|
972053c699 | ||
|
|
9db7896828 | ||
|
|
be6f93735d | ||
|
|
3bcea249ac | ||
|
|
8ee32dfa88 | ||
|
|
e2f9411b46 | ||
|
|
0bd68c3817 | ||
|
|
f03505ab67 | ||
|
|
f1ae795c0f | ||
|
|
50fcda2763 | ||
|
|
331aa382f9 | ||
|
|
3c160c2f13 | ||
|
|
4fd617a32f | ||
|
|
0d294eb218 | ||
|
|
a49e3b90b0 | ||
|
|
201392f22e | ||
|
|
3fa4ee772f | ||
|
|
529c83c572 | ||
|
|
6a9e56e9d9 | ||
|
|
716e80fb84 | ||
|
|
80067b806d | ||
|
|
315073f9a7 | ||
|
|
a1dbbba1a1 | ||
|
|
cb8a0b6853 | ||
|
|
a5a29f7ad3 | ||
|
|
8e14ef7c0c | ||
|
|
c270391772 | ||
|
|
e466cb6e30 | ||
|
|
f0df9dc0fb | ||
|
|
b31c08083a | ||
|
|
145a8d5b67 | ||
|
|
60d7a4e7ee | ||
|
|
b52ffd09b2 | ||
|
|
58278ab1e4 | ||
|
|
000cf5fd5a | ||
|
|
216b58e392 | ||
|
|
279cce49ba | ||
|
|
8184b77b13 | ||
|
|
b8b731ab04 | ||
|
|
1d4c39d13d | ||
|
|
ac26f5b2ef | ||
|
|
c07447d8f5 | ||
|
|
833ddf5f4c | ||
|
|
4dc4f468bb | ||
|
|
1aff69d3cf | ||
|
|
f2f63a703e | ||
|
|
97e6b17f96 | ||
|
|
b90d284b08 | ||
|
|
840a65c630 | ||
|
|
e5c89d4881 | ||
|
|
0fc6638294 | ||
|
|
7c7724e41c | ||
|
|
31319711dd | ||
|
|
8954729d55 | ||
|
|
ae4dc442b9 | ||
|
|
919ff414e6 | ||
|
|
b861703dad | ||
|
|
2f17647cd3 | ||
|
|
f8d2c7eba3 | ||
|
|
e511b2faf9 | ||
|
|
301e6b194a | ||
|
|
1208ca3ad4 | ||
|
|
84e7cd0df8 | ||
|
|
7e1077426e | ||
|
|
1e2c437a08 | ||
|
|
a7ce1d1225 | ||
|
|
1d3223e9c6 | ||
|
|
b01f3f4bb5 | ||
|
|
ee4cd11ae1 | ||
|
|
154f8b307e | ||
|
|
7aac7872e3 | ||
|
|
b2630032e7 | ||
|
|
80136b602b | ||
|
|
3df29ed2a9 | ||
|
|
69658f2022 | ||
|
|
5fd0a0831f | ||
|
|
43b299ebd1 | ||
|
|
9612304023 | ||
|
|
3154e59b36 | ||
|
|
2d5a496678 | ||
|
|
4c1c322b54 | ||
|
|
e9f3281694 | ||
|
|
c3534affdb | ||
|
|
c6e62b3263 | ||
|
|
d8ce177ce7 | ||
|
|
726bfbefb0 | ||
|
|
5c4a6487c0 | ||
|
|
3145433099 | ||
|
|
bdf6844b74 | ||
|
|
9ad430915c | ||
|
|
60bbd71a22 | ||
|
|
c96498758f | ||
|
|
f4600bd8eb | ||
|
|
7202a5734c | ||
|
|
8edb6eaa81 | ||
|
|
b8eecc05fd | ||
|
|
7fc5aef553 | ||
|
|
bee6b7f946 | ||
|
|
3bedfb6ac8 | ||
|
|
f49bf0192b | ||
|
|
f36ac5272b | ||
|
|
f0fe446f7f | ||
|
|
d9c4720a3e | ||
|
|
4de5d8f2a3 | ||
|
|
8651311016 | ||
|
|
1d27c5a14c | ||
|
|
b0b8ff2d49 | ||
|
|
cd03e1fc74 | ||
|
|
b273a449e3 | ||
|
|
b637867f9e | ||
|
|
41d5792b27 | ||
|
|
d22712a25b | ||
|
|
33968ee5da | ||
|
|
9baf1774e0 | ||
|
|
9ca66e4061 | ||
|
|
db2d34f840 | ||
|
|
195cc61df7 | ||
|
|
aaa530e72b | ||
|
|
fa856ee905 | ||
|
|
2bf7a5c4d3 | ||
|
|
780b982635 | ||
|
|
74bbc1f19f | ||
|
|
e314545f2e | ||
|
|
f1a3a12c1c | ||
|
|
ef080c3cb1 | ||
|
|
7313db5ac0 | ||
|
|
bf9aa524ed | ||
|
|
b59aa0827e | ||
|
|
2584f1293e | ||
|
|
de9d28adea | ||
|
|
b660287779 | ||
|
|
962536bc83 | ||
|
|
ee4fcf8100 | ||
|
|
9a4ed1a19d | ||
|
|
c1d0702b4d | ||
|
|
af1c46543b | ||
|
|
e2f5486987 | ||
|
|
b0d390aaf1 | ||
|
|
bae1b42394 | ||
|
|
a2533edd57 | ||
|
|
7b88c198fe | ||
|
|
c49cb0c119 | ||
|
|
03aabeb848 | ||
|
|
1d3a837f7a | ||
|
|
92adc18b8f | ||
|
|
e4697c8ff1 | ||
|
|
b741f1a580 | ||
|
|
8ee6de4162 | ||
|
|
2b9e7db924 | ||
|
|
49384ce294 | ||
|
|
ac59fff346 | ||
|
|
a3e9f152d8 | ||
|
|
ffe6a81b9a | ||
|
|
9bb051b4eb | ||
|
|
c1465a890f | ||
|
|
c3ee3318d7 | ||
|
|
272976f0b7 | ||
|
|
4724b170b1 | ||
|
|
337bd4bcef | ||
|
|
0604c78453 | ||
|
|
c8169adf7c | ||
|
|
7b610d131c | ||
|
|
18da55453f | ||
|
|
2aeab8b672 | ||
|
|
9c21707a55 | ||
|
|
b02ac833ad | ||
|
|
4de912cf41 | ||
|
|
ed260c6e20 | ||
|
|
fab38f693d | ||
|
|
aedbd52e9d | ||
|
|
4cbcb9d99c | ||
|
|
e967d15b4e | ||
|
|
bb43cc63ec | ||
|
|
ca176c319d | ||
|
|
17c960ecd4 | ||
|
|
b766ae3498 | ||
|
|
faf4c817cd | ||
|
|
b4e1f283c9 | ||
|
|
52c83d592c | ||
|
|
c8caea0d30 | ||
|
|
7a6c54d8e7 | ||
|
|
7082e52a4f | ||
|
|
6cdca617e0 | ||
|
|
a1adc1a75a | ||
|
|
b16bec704a | ||
|
|
664a8c79a1 | ||
|
|
bbf3d8e1a4 | ||
|
|
a35146440c | ||
|
|
8e79fafca9 | ||
|
|
6f8780d3cc | ||
|
|
264065a355 | ||
|
|
b606e4cd1a | ||
|
|
01d0eeaed0 | ||
|
|
8c4e24e65d | ||
|
|
19c9f9698d | ||
|
|
ae87c1b578 | ||
|
|
c42b1f5548 | ||
|
|
87ffbb0a85 | ||
|
|
702851a958 | ||
|
|
650f200a0b | ||
|
|
14d215bdf3 | ||
|
|
12aebc2fe9 | ||
|
|
f41b051ec7 | ||
|
|
25144eee89 | ||
|
|
0c62147536 | ||
|
|
7b282e21de | ||
|
|
c1fbe6d84c | ||
|
|
e20cbe4170 | ||
|
|
394955a03f | ||
|
|
16b4f5d065 | ||
|
|
c95295d8b4 | ||
|
|
658dce2607 | ||
|
|
01f8d0a27e | ||
|
|
39e1bfc84f | ||
|
|
e394416fa7 | ||
|
|
f1108bc0e2 | ||
|
|
ff31815d49 | ||
|
|
604aa63b47 | ||
|
|
ec4d036f50 | ||
|
|
1bf1c4ac63 | ||
|
|
981d46fbd4 | ||
|
|
eb6a353c31 | ||
|
|
ff673b1941 | ||
|
|
8b55cf8a3a | ||
|
|
d8682b4403 | ||
|
|
40a4bf195a | ||
|
|
312c5cbc3f | ||
|
|
f314c56ef0 | ||
|
|
ea8e5180ff | ||
|
|
7f76c3f2ce | ||
|
|
e4c5e99d0f | ||
|
|
80cfca5de2 | ||
|
|
9556a14de9 | ||
|
|
2025fc8325 | ||
|
|
2dd0f6a9ba | ||
|
|
a42039d6e5 | ||
|
|
7fafa8adfb | ||
|
|
f789657552 | ||
|
|
3e183bc10e | ||
|
|
16e5d93be3 | ||
|
|
6515e06a13 | ||
|
|
9ae0b32318 | ||
|
|
4cb3bc4185 | ||
|
|
f9ca24598e | ||
|
|
3ccc892d6a | ||
|
|
d7cacea843 | ||
|
|
e30233ac74 | ||
|
|
7c57631fcf | ||
|
|
0adc084dad | ||
|
|
e22199817c | ||
|
|
78f691d006 | ||
|
|
749bae1f16 | ||
|
|
1043e24322 | ||
|
|
a6d10b1fa7 | ||
|
|
a3159423f8 | ||
|
|
ecb5ca321b | ||
|
|
fd827fdfd8 | ||
|
|
92d77b14d5 | ||
|
|
be67d89d8b | ||
|
|
ddd1ce732a | ||
|
|
012d82183c | ||
|
|
f9c98ebcb3 | ||
|
|
10fe861dde | ||
|
|
16c027ecab | ||
|
|
cc578e7cc5 | ||
|
|
6972d3c4f9 | ||
|
|
46b164f2fb | ||
|
|
5431307527 | ||
|
|
79bf194ed6 | ||
|
|
506e670aa7 | ||
|
|
fdfe164dd1 | ||
|
|
af37056179 | ||
|
|
b0fc7187cf | ||
|
|
33ad1a7a86 | ||
|
|
dd72fb4ca5 | ||
|
|
e6c5f76872 | ||
|
|
14aa22d590 | ||
|
|
5ed4293641 | ||
|
|
f9fefcda57 | ||
|
|
99b40293db | ||
|
|
9b06e85f94 | ||
|
|
93d1d40ea5 | ||
|
|
98597c047a | ||
|
|
a5c1f4b0ee | ||
|
|
3d4c98d981 | ||
|
|
384e7dedb5 | ||
|
|
7df4453560 | ||
|
|
d406a1c341 | ||
|
|
6671d97b4a | ||
|
|
d02de72830 | ||
|
|
08f5172028 | ||
|
|
04f062547d | ||
|
|
4717d783dc | ||
|
|
93af064b36 | ||
|
|
c78d73d727 | ||
|
|
b69b3228be | ||
|
|
377f54700d | ||
|
|
d276339c80 | ||
|
|
b982a6a762 | ||
|
|
536fe637aa | ||
|
|
69f36eaa25 | ||
|
|
d6927a70bb | ||
|
|
1b1892a187 | ||
|
|
5bea71cd5c | ||
|
|
bb8d4e70ae | ||
|
|
8d8c7e8b7b | ||
|
|
9ff1f4d7b4 | ||
|
|
3a60dfe025 | ||
|
|
d358854e16 | ||
|
|
129587e94a | ||
|
|
0f575f4639 | ||
|
|
7aac741571 | ||
|
|
b8a9da8a4e | ||
|
|
be6b974334 | ||
|
|
194e81205b | ||
|
|
d711dcc99d | ||
|
|
3b72a12540 | ||
|
|
38a1b7765a | ||
|
|
02f2b8b6f0 | ||
|
|
7bfa75102c | ||
|
|
b0f3e7351c | ||
|
|
b5fa401db9 | ||
|
|
41f2710dea | ||
|
|
f19dda57f0 | ||
|
|
cc4a99ad80 | ||
|
|
1c1a3fc417 | ||
|
|
e97be5850b | ||
|
|
2c302654b7 | ||
|
|
3ee4dc77b2 | ||
|
|
db55f314c9 | ||
|
|
0b536b287f | ||
|
|
6f298a9917 | ||
|
|
70f829a2e5 | ||
|
|
1dfe07003f | ||
|
|
286b908062 | ||
|
|
4ec028e736 | ||
|
|
35a6d1437a | ||
|
|
7e3cb3de89 | ||
|
|
bd945039f1 | ||
|
|
46743c8f15 | ||
|
|
9b75284447 | ||
|
|
dca3b0052a | ||
|
|
6d05bb2de5 | ||
|
|
8b2e8d3804 | ||
|
|
1a2ab19ab4 | ||
|
|
04f010aa7b | ||
|
|
25323b4a3a | ||
|
|
f353c022f6 | ||
|
|
9d8b3d3428 | ||
|
|
e4b06772c0 | ||
|
|
a2b5c3ea08 | ||
|
|
f632e95600 | ||
|
|
4b5da8c6d4 | ||
|
|
77d7ffd10a | ||
|
|
d2f720011a | ||
|
|
6329a7711d | ||
|
|
fd14d044e3 | ||
|
|
6368d507e1 | ||
|
|
205b7f2401 | ||
|
|
f7d10f9530 | ||
|
|
66154bb51e | ||
|
|
fac4ad5313 | ||
|
|
fee63891ac | ||
|
|
efa979ee03 | ||
|
|
c756346357 | ||
|
|
cc95db25cc | ||
|
|
44970c3321 | ||
|
|
43c7934af7 | ||
|
|
3e7b51163c | ||
|
|
4d5f8a53f0 | ||
|
|
0b73ca8318 | ||
|
|
754cfc3bfd | ||
|
|
2ed1a5c06a | ||
|
|
b2073df3c3 | ||
|
|
6267edaa81 | ||
|
|
292f2de3e6 | ||
|
|
7803dc8be3 | ||
|
|
2a1260b79e | ||
|
|
f9ec438b7f | ||
|
|
de544c4856 | ||
|
|
55e04dd520 | ||
|
|
b2d06f900b | ||
|
|
b92ec71810 | ||
|
|
3a4199240e | ||
|
|
157de12bdf | ||
|
|
7c0c9fccdb | ||
|
|
2cb29d06b3 | ||
|
|
1fdeb50d93 | ||
|
|
f59632ae59 | ||
|
|
67b503da44 | ||
|
|
a351de6904 | ||
|
|
f94742abd5 | ||
|
|
891182637e | ||
|
|
086681c915 | ||
|
|
3970d2d02b | ||
|
|
2b3fddd015 | ||
|
|
30fa0480a3 | ||
|
|
320a81ce69 | ||
|
|
950411ef56 | ||
|
|
cb9cf084c0 | ||
|
|
bb18af09ae | ||
|
|
049bf0c7f9 | ||
|
|
ebc73ef775 | ||
|
|
1bd6f59355 | ||
|
|
c16396a690 | ||
|
|
32a9fe3e9c | ||
|
|
f48d133bc6 | ||
|
|
0678526d7d | ||
|
|
26d3e8371f | ||
|
|
6768f614c7 | ||
|
|
171dc84df1 | ||
|
|
5ca6513c04 | ||
|
|
41aeb0ac80 | ||
|
|
f871c4adef | ||
|
|
ad4d0e89b1 | ||
|
|
0d0c49caa1 | ||
|
|
7cbc7bdcfb | ||
|
|
6b46c8ed4a | ||
|
|
e33ffd1c8a | ||
|
|
8dce9cc938 | ||
|
|
f06218f8e3 | ||
|
|
5711eef2be | ||
|
|
db6aac603c | ||
|
|
f10e928106 | ||
|
|
99d963b99c | ||
|
|
5d35c22238 | ||
|
|
54fc11a235 | ||
|
|
ec99df3144 | ||
|
|
d722035883 | ||
|
|
52139fbaa0 | ||
|
|
88854eb558 | ||
|
|
c82bba01ee | ||
|
|
eaa33a03d7 | ||
|
|
89e8518f31 | ||
|
|
c7bf2e1da8 | ||
|
|
bf904a6afa | ||
|
|
43c14ae71b | ||
|
|
4abb8ef3c9 | ||
|
|
e46b92dd7d | ||
|
|
1a25faa5b9 | ||
|
|
3f4bf5f512 | ||
|
|
ae7dbf15ed | ||
|
|
b22320c48f | ||
|
|
61204e8d35 | ||
|
|
b0704c654c | ||
|
|
f40f8a8873 | ||
|
|
560a7db506 | ||
|
|
15baa8f70e | ||
|
|
97a7637294 | ||
|
|
3454656207 | ||
|
|
7dff6f26bc | ||
|
|
9e835a23fd | ||
|
|
c0259fb6ce | ||
|
|
acf106220b | ||
|
|
5d4dc9c907 | ||
|
|
2b9a56af7f | ||
|
|
f1e3ac65ac | ||
|
|
143f72cf6b | ||
|
|
5c8e49296c | ||
|
|
b2558b703c | ||
|
|
bf9d87106e | ||
|
|
5b7f507d9b | ||
|
|
59a7835ace | ||
|
|
2495838fe3 | ||
|
|
bab687bedf | ||
|
|
6467c3c8ee | ||
|
|
66c2b7aaa6 | ||
|
|
ab72c52661 | ||
|
|
f0bf1b8a54 | ||
|
|
119251719f | ||
|
|
0348400132 | ||
|
|
813473805b | ||
|
|
fe6368561b | ||
|
|
7ff06f424d | ||
|
|
31958592c7 | ||
|
|
adc21f4f75 | ||
|
|
9cecd89d6f | ||
|
|
d866b9b4d4 | ||
|
|
93f12baf51 | ||
|
|
78d6fd634b | ||
|
|
b5fc19f08a | ||
|
|
2dae6a6546 | ||
|
|
b6bba46391 | ||
|
|
b791d97116 | ||
|
|
6aa8255f34 | ||
|
|
98e2140761 | ||
|
|
a59e064778 | ||
|
|
655c4c66a7 | ||
|
|
407c128f65 | ||
|
|
59a261a5be | ||
|
|
ba4e1afefe | ||
|
|
98b53b81d8 | ||
|
|
8270cc0aa2 | ||
|
|
74207b1a87 | ||
|
|
77983445ce | ||
|
|
162190bcb8 | ||
|
|
86b92b20b7 | ||
|
|
2f5b60d548 | ||
|
|
c19661c977 | ||
|
|
82d101ca27 | ||
|
|
32f9c4e670 | ||
|
|
34c7225ab7 | ||
|
|
b02eb502e4 | ||
|
|
7d6b3dfd20 | ||
|
|
3ac39968d2 | ||
|
|
2b24ac54a0 | ||
|
|
6da6b794c7 | ||
|
|
ed689e27c9 | ||
|
|
186f9c3f18 | ||
|
|
42cdde3203 | ||
|
|
b9091702e9 | ||
|
|
d42ecbe74e | ||
|
|
e6c5446d63 | ||
|
|
cc277211b3 | ||
|
|
6703c15c52 | ||
|
|
4ecdaf573e | ||
|
|
71ec3e61be | ||
|
|
216fdb2393 | ||
|
|
c39acc6e3c | ||
|
|
d97b0478a7 | ||
|
|
d15d64eb67 | ||
|
|
3acd2656ee | ||
|
|
a4b003534a | ||
|
|
8752538a02 | ||
|
|
bde435753a | ||
|
|
d347e6fc5f | ||
|
|
27b01d3642 | ||
|
|
b78677e285 | ||
|
|
f8f6c74bcb | ||
|
|
7ce123939b | ||
|
|
e7b02cfb15 | ||
|
|
5931077b08 | ||
|
|
a521bdc0e3 | ||
|
|
80da565609 | ||
|
|
6bc46e4598 | ||
|
|
6562258db5 | ||
|
|
c219995218 | ||
|
|
62035431ed | ||
|
|
fa1fbca7dc | ||
|
|
391b7476b3 | ||
|
|
9c04ce665f | ||
|
|
dd87268197 | ||
|
|
8d9af59db2 | ||
|
|
1b754a35ff | ||
|
|
7230f91f61 | ||
|
|
93edfc315c | ||
|
|
74c8269531 | ||
|
|
acb6c0fc83 | ||
|
|
553d4cce93 | ||
|
|
ca81f144e6 | ||
|
|
ec84960347 | ||
|
|
38db0764af | ||
|
|
a647f63bb0 | ||
|
|
5b7087cc9e | ||
|
|
1a6fcd5da6 | ||
|
|
e31dd9f553 | ||
|
|
22844716d1 | ||
|
|
6abed76f70 | ||
|
|
72ff502e0f | ||
|
|
2b781df32b | ||
|
|
bf601c3906 | ||
|
|
b753e0ebb0 | ||
|
|
564211aceb | ||
|
|
538c759fef | ||
|
|
95edc34100 | ||
|
|
98682a2da9 | ||
|
|
33581fa61d | ||
|
|
b02e0aae98 | ||
|
|
6fa4e1cb6d | ||
|
|
9f2ec22e95 | ||
|
|
65b2e506b1 | ||
|
|
8bc07b5286 | ||
|
|
fe0af63795 | ||
|
|
44ce7f4c67 | ||
|
|
252936134b | ||
|
|
e255b06945 | ||
|
|
d726568a23 | ||
|
|
66880a6de7 | ||
|
|
fda622a0c0 | ||
|
|
efa7d10f40 | ||
|
|
348a3fabab | ||
|
|
1bbaee605c | ||
|
|
22edf7a2b3 | ||
|
|
3ffcc29249 | ||
|
|
21f1fe52c0 | ||
|
|
99840c9e4f | ||
|
|
3194fe7d8e | ||
|
|
81df72b0cb | ||
|
|
57b056ac43 | ||
|
|
c5876d0d48 | ||
|
|
b5e65401b6 | ||
|
|
ebea5b48ea | ||
|
|
7d081e581a | ||
|
|
5e819cf04b | ||
|
|
fd9ab43681 | ||
|
|
4935cdc722 | ||
|
|
26a3c7ad6a | ||
|
|
c358216ad9 | ||
|
|
bb9302143c | ||
|
|
3a73553aac | ||
|
|
6447a17e3e | ||
|
|
4bd5c8ffb3 | ||
|
|
89f137b211 | ||
|
|
3425572c66 | ||
|
|
ad50875f9c | ||
|
|
34e5645dab | ||
|
|
e8ae91c230 | ||
|
|
44b83994fa | ||
|
|
201f585350 | ||
|
|
e4d2f1925e | ||
|
|
658c116eac | ||
|
|
dbbedee77f | ||
|
|
16ac9ea061 | ||
|
|
6afbc71b4a | ||
|
|
71263863ad | ||
|
|
05232065f8 | ||
|
|
f289ae4143 | ||
|
|
91703ecec4 | ||
|
|
6fb0858b87 | ||
|
|
f1c6620df9 | ||
|
|
08fed9a5ee | ||
|
|
eb28b3b05b | ||
|
|
f0c354b0c9 | ||
|
|
07d88e86a2 | ||
|
|
f41a3b9bb2 | ||
|
|
bfd9e76f40 | ||
|
|
38ce208a43 | ||
|
|
fcd148b8d5 | ||
|
|
fc6c3774b0 | ||
|
|
18023d2e18 | ||
|
|
467e834ad6 | ||
|
|
629d9e7ae0 | ||
|
|
4487d292e8 | ||
|
|
76711b9a66 | ||
|
|
b54c749e43 | ||
|
|
d82fd421ed | ||
|
|
abdcadb5fa | ||
|
|
fa3891e383 | ||
|
|
f1dc0f95c8 | ||
|
|
5c721d243a | ||
|
|
2770384f1f | ||
|
|
f4e5b83039 | ||
|
|
124681605b | ||
|
|
a217faae7c | ||
|
|
184c39bbb7 | ||
|
|
508e2a70bb | ||
|
|
5aac56fe96 | ||
|
|
dab7dad966 | ||
|
|
25e48d6cae | ||
|
|
9b743e55d1 | ||
|
|
dc1f9edfaf | ||
|
|
b6b68edf1e | ||
|
|
a2320b99ae | ||
|
|
be01e28068 | ||
|
|
d6084083a5 | ||
|
|
019bf5102c | ||
|
|
a1633224d1 | ||
|
|
e62bd26cb9 | ||
|
|
c29f517292 | ||
|
|
d80144f80c | ||
|
|
4733c84a86 | ||
|
|
23f3d2095b | ||
|
|
4f1f2b6fc6 | ||
|
|
1ea70b085f | ||
|
|
6c0b395f4a | ||
|
|
0ee67f186f | ||
|
|
d133addbaa | ||
|
|
683991b1c9 | ||
|
|
32ac02007b | ||
|
|
d716617ae0 | ||
|
|
26e1f015d2 | ||
|
|
1c94093a4b | ||
|
|
27eccd456a | ||
|
|
eed4447560 | ||
|
|
3c8d0ebd52 | ||
|
|
7ec0d2f2cc | ||
|
|
35da91a997 | ||
|
|
788747c071 | ||
|
|
36eb131289 | ||
|
|
f231f28818 | ||
|
|
aebdc89f77 | ||
|
|
4a3a379871 | ||
|
|
a7f27add2d | ||
|
|
cd1d4247cf | ||
|
|
6d618c4b78 | ||
|
|
ad469531ff | ||
|
|
cf9b4b1246 | ||
|
|
18a2692dc1 | ||
|
|
a2dad982f8 | ||
|
|
8f27b6a4c9 | ||
|
|
21c4022fca | ||
|
|
237933855a | ||
|
|
dff7068a03 | ||
|
|
8f28a85a6d | ||
|
|
2414eb2598 | ||
|
|
4851f6bffd | ||
|
|
948be36d3c | ||
|
|
edd088927d | ||
|
|
4cfe8dd95e | ||
|
|
e1ce81c5bf | ||
|
|
0f40b5f022 | ||
|
|
94c5ffa92e | ||
|
|
3c9bf56767 | ||
|
|
9024acb16e | ||
|
|
7732402122 | ||
|
|
2059bce6a7 | ||
|
|
499c86a8b8 | ||
|
|
ef084eb145 | ||
|
|
3f3ae7c38f | ||
|
|
83d762287f | ||
|
|
5af0acf147 | ||
|
|
907dfee6f7 | ||
|
|
d587d24603 | ||
|
|
c246b8f164 | ||
|
|
deecafa053 | ||
|
|
f8810106a2 | ||
|
|
8e35fbe532 | ||
|
|
b1fdccde6e | ||
|
|
6741f100a1 | ||
|
|
e05e9ea1b2 | ||
|
|
197341de5e | ||
|
|
2933482be3 | ||
|
|
c7ce23239f | ||
|
|
79115f7439 | ||
|
|
4457103672 | ||
|
|
d204875f72 | ||
|
|
c690e73b1a | ||
|
|
b5d39c5f21 | ||
|
|
7f8834cb04 | ||
|
|
0dab7e293c | ||
|
|
8f016880af | ||
|
|
f471462a84 | ||
|
|
58eec8df1e | ||
|
|
2655b8b43a | ||
|
|
ea86c043a4 | ||
|
|
c1faa616bc | ||
|
|
a68bf5a30d | ||
|
|
9568b8e0e5 | ||
|
|
b34321ef87 | ||
|
|
4971f1c5bf | ||
|
|
962b52bd5b | ||
|
|
9449bfa414 | ||
|
|
5b8e9066c6 | ||
|
|
8690be7fd2 | ||
|
|
497267016b | ||
|
|
0468f850c2 | ||
|
|
b9e7d4e30c | ||
|
|
0e7734b555 | ||
|
|
e81dcce5b3 | ||
|
|
38bd1f7e1c | ||
|
|
36ad9704a2 | ||
|
|
a6c05df362 | ||
|
|
f6b70fda71 | ||
|
|
8cb4e75f70 | ||
|
|
da1815ac2b | ||
|
|
f7357f2d10 | ||
|
|
d9c92c5ddd | ||
|
|
c82bdb6405 | ||
|
|
eec8ee5830 | ||
|
|
e67eb3c0d8 | ||
|
|
9c101759f6 | ||
|
|
a55ee92590 | ||
|
|
5ccfc97dab | ||
|
|
d6dd88ec3d | ||
|
|
8557d83599 | ||
|
|
94cf1f8698 | ||
|
|
9ada35c3a3 | ||
|
|
79b0c906fa | ||
|
|
a0688f1dba | ||
|
|
f91e8fecee | ||
|
|
1b363babe2 | ||
|
|
73843cb54d | ||
|
|
a2ccfc2116 | ||
|
|
fe104e2bad | ||
|
|
35e3e9f4ff | ||
|
|
b2a1cd9716 | ||
|
|
14f58eae4b | ||
|
|
5cec000618 | ||
|
|
4805a5287d | ||
|
|
4789dc5b30 | ||
|
|
5a35099043 | ||
|
|
4cd0128919 | ||
|
|
61e9b80f67 | ||
|
|
dcd881ba6c | ||
|
|
d40a67ce68 | ||
|
|
1c1e7ca62a | ||
|
|
d3831d511b | ||
|
|
0942e93144 | ||
|
|
98d3eba8e8 | ||
|
|
ff3db03696 | ||
|
|
3608c31d22 | ||
|
|
8d504d9cee | ||
|
|
782921f6e0 | ||
|
|
0694aabb45 | ||
|
|
604b35dfde | ||
|
|
4c308bf5d0 | ||
|
|
7a53ca7f8e | ||
|
|
7c51f04140 | ||
|
|
488b326e0f | ||
|
|
1e0c0a35ba | ||
|
|
bf044c1ccc | ||
|
|
c9caa7f034 | ||
|
|
1b8966b3a4 | ||
|
|
01d4d404c0 | ||
|
|
354bbf820f | ||
|
|
7620f9ebbe | ||
|
|
9c2c668a04 | ||
|
|
b6f5a5712b | ||
|
|
9e9df6eb16 | ||
|
|
f510c993a6 | ||
|
|
8ddcbaac27 | ||
|
|
3fcab72900 | ||
|
|
70aa2233e2 | ||
|
|
8123a2924d | ||
|
|
dd3c308b09 | ||
|
|
e56ca2ffd6 | ||
|
|
57c98c363c | ||
|
|
2211508061 | ||
|
|
848e41919d | ||
|
|
dac613a8bb | ||
|
|
a1735278df | ||
|
|
3730bd04a4 | ||
|
|
eee3445d2f | ||
|
|
8bf473dc3a | ||
|
|
e106dda794 | ||
|
|
fc35d2a35c | ||
|
|
aef9ff0d38 | ||
|
|
192fb46d1d | ||
|
|
1dd4eb05f2 | ||
|
|
79f0c494fa | ||
|
|
7caeb47637 | ||
|
|
ffef339ebd | ||
|
|
817153b20b | ||
|
|
686eb2e786 | ||
|
|
53d5192477 | ||
|
|
a172f5fe85 | ||
|
|
288408795b | ||
|
|
4b5a811b08 | ||
|
|
c1259d8b6e | ||
|
|
3acbe431f7 | ||
|
|
40f381257d | ||
|
|
beec983f21 | ||
|
|
d20750012e | ||
|
|
e31c9d74fa | ||
|
|
78adc388df | ||
|
|
609413cda4 | ||
|
|
63e5d6a94a | ||
|
|
fd5970b647 | ||
|
|
af38b8f92b | ||
|
|
e676e65f9e | ||
|
|
4c479301ff | ||
|
|
98178947ae | ||
|
|
0dbf3b462b | ||
|
|
cd9f8b569b | ||
|
|
6b23728efa | ||
|
|
ff0f7ee483 | ||
|
|
74498c3ac9 | ||
|
|
7a61e740e8 | ||
|
|
81e6b55c39 | ||
|
|
e439ac0e0e | ||
|
|
7b9d784a64 | ||
|
|
56b2630a1c | ||
|
|
6d5597a732 | ||
|
|
c0a9345358 | ||
|
|
2e4ad81fff | ||
|
|
1aad85a4f9 | ||
|
|
fbd2993239 | ||
|
|
203228bd05 | ||
|
|
da7edebe90 | ||
|
|
c7444a189e | ||
|
|
29235c5fa6 | ||
|
|
bf8374ff9f | ||
|
|
ba05e85e48 | ||
|
|
a9aab0702c | ||
|
|
b5cf83d501 | ||
|
|
1cc2e6303a | ||
|
|
4509a07fff | ||
|
|
ea419f6d40 | ||
|
|
c9b6707468 | ||
|
|
cf512a35a7 | ||
|
|
bdd3e5343d | ||
|
|
80fd8cd338 | ||
|
|
eb48592083 | ||
|
|
a45cb25002 | ||
|
|
21ec116769 | ||
|
|
1d4775a94b | ||
|
|
4cde9a7e9e | ||
|
|
709ba72777 | ||
|
|
0e56b8c575 | ||
|
|
558a087e37 | ||
|
|
7d96fe8b65 | ||
|
|
2f3e8986ab | ||
|
|
df359ba0fa | ||
|
|
31fa60884f | ||
|
|
15be227920 | ||
|
|
fdedfd54c7 | ||
|
|
7d55eb4b44 | ||
|
|
61ac7ae31e | ||
|
|
353e141036 | ||
|
|
cb4332842f | ||
|
|
004d219c97 | ||
|
|
94561e6815 | ||
|
|
ce3af4961b | ||
|
|
bbd81e7d9c | ||
|
|
8b1d198efd | ||
|
|
7a3bafc961 | ||
|
|
512eed9b04 | ||
|
|
38adf640e9 | ||
|
|
f4d8d73970 | ||
|
|
5a50285dee | ||
|
|
ca4ea0719f | ||
|
|
4c6251bf28 | ||
|
|
22c12c7366 | ||
|
|
8f49d1591f | ||
|
|
a97dbab2ae | ||
|
|
4cb8261d3b | ||
|
|
059e2d740f | ||
|
|
587d1c9d74 | ||
|
|
ab56c96170 | ||
|
|
efa4270429 | ||
|
|
0fbe5d888a | ||
|
|
b68f81179e | ||
|
|
6a8c1af5f9 | ||
|
|
98f287559b | ||
|
|
1a53d85f6a | ||
|
|
05b168aa04 | ||
|
|
a68d856074 | ||
|
|
d5dac9c6cc | ||
|
|
e9f7f42c03 | ||
|
|
7b8265d4a3 | ||
|
|
5715f4c2cb | ||
|
|
350debb66c | ||
|
|
267cd3660b | ||
|
|
bc1c0c3c6d | ||
|
|
c420f69da8 | ||
|
|
2151d96303 | ||
|
|
c48c65d0ce | ||
|
|
1c0b706b94 | ||
|
|
2dca3d6f5a | ||
|
|
0992636f8c | ||
|
|
86d3f2b4ed | ||
|
|
b78b4038f6 | ||
|
|
84c14349dc | ||
|
|
9916e34006 | ||
|
|
a729b42e5d | ||
|
|
01f8129ed0 | ||
|
|
fd85763fb4 | ||
|
|
c278ffe2cb | ||
|
|
902c76a781 | ||
|
|
4daed0070a | ||
|
|
a4d055b3ac | ||
|
|
e6ae6c6f04 | ||
|
|
de54ceeb40 | ||
|
|
77fe00df30 | ||
|
|
4ae3e63dea | ||
|
|
3329839dbe | ||
|
|
ca10920bb5 | ||
|
|
b41957ce5c | ||
|
|
3db6699018 | ||
|
|
5284ca90ef | ||
|
|
628cdff4fa | ||
|
|
af0c6f9233 | ||
|
|
7697bbfa4e | ||
|
|
642a455a9c | ||
|
|
6abfa2859b | ||
|
|
20c2225d8f | ||
|
|
5e7759b697 | ||
|
|
1ce8d2b31d | ||
|
|
9fbecb5af6 | ||
|
|
1223469be9 | ||
|
|
5eae3ddd8a | ||
|
|
3d0b6e6ea1 | ||
|
|
c6c53548ac | ||
|
|
3efe2d1e05 | ||
|
|
7c87b53517 | ||
|
|
a461c97bcf | ||
|
|
67a6d6c1e3 | ||
|
|
8b8e427a2b | ||
|
|
7d5c263ab2 | ||
|
|
79ac53b2d9 | ||
|
|
a704412dee | ||
|
|
24e2338769 | ||
|
|
bc240f82ef | ||
|
|
a2ad68406d | ||
|
|
3d807d2331 | ||
|
|
e6a7b484ba | ||
|
|
a62371829f | ||
|
|
fb98336713 | ||
|
|
ebadb4db0a | ||
|
|
9a480eb710 | ||
|
|
03ecde8b83 | ||
|
|
0291b78bfa | ||
|
|
377e6fad25 | ||
|
|
e75c955a68 | ||
|
|
6df356327d | ||
|
|
7a57586f90 | ||
|
|
1e2bad270d | ||
|
|
688d983b25 | ||
|
|
fa834a76ef | ||
|
|
5cb88efc38 | ||
|
|
6b64c43851 | ||
|
|
704e6c5448 | ||
|
|
072d7379df | ||
|
|
df1b756a43 | ||
|
|
30269d9d95 | ||
|
|
d29a1de980 | ||
|
|
57f5ccff81 | ||
|
|
69374bfa11 | ||
|
|
d9fd330216 | ||
|
|
312f62d98f | ||
|
|
0d408055b2 | ||
|
|
496ae42d72 | ||
|
|
3ab86543ad | ||
|
|
ce7926cfa4 | ||
|
|
48c81b188c | ||
|
|
21b241bbbe | ||
|
|
934d6fc267 | ||
|
|
a0ce2daa2e | ||
|
|
006d77239b | ||
|
|
303d31bde7 | ||
|
|
737fbeccde | ||
|
|
ec17dc9830 | ||
|
|
0f710ea3be | ||
|
|
bd4eec4527 | ||
|
|
c78252e0d5 | ||
|
|
b1f70982bf | ||
|
|
6128fb4f19 | ||
|
|
ee915254e7 | ||
|
|
d835d4aae6 | ||
|
|
5945d0ebee | ||
|
|
3d3aacdcb1 | ||
|
|
c3ce6cff72 | ||
|
|
6d7a01fb4e | ||
|
|
8582e09e73 | ||
|
|
90744f2965 | ||
|
|
03d0776fdc |
213
.clang-format
@@ -1,105 +1,216 @@
|
||||
BasedOnStyle: Chromium
|
||||
Language: Cpp
|
||||
Standard: Cpp11
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -1
|
||||
AlignAfterOpenBracket: false
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignConsecutiveMacros: true
|
||||
AlignEscapedNewlines: true
|
||||
AlignOperands: false
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: DontAlign
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: true
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLambdasOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: No
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BreakBeforeBraces: false
|
||||
BreakBeforeBinaryOperators: false
|
||||
BreakBeforeBraces: Stroustrup
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: true
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 0
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
QualifierAlignment: Leave
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 2
|
||||
Cpp11BracedListStyle: false
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: true
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: true
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
PackConstructorInitializers: BinPack
|
||||
BasedOnStyle: ''
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
FixNamespaceComments: true
|
||||
IncludeBlocks: Preserve
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: true
|
||||
IndentCaseBlocks: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: 2
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentRequiresClause: true
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertBraces: false
|
||||
InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
LambdaBodyIndentation: Signature
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 100
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 0
|
||||
PenaltyBreakBeforeFirstCallParameter: 0
|
||||
PenaltyBreakComment: 0
|
||||
PenaltyBreakFirstLessLess: 0
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakString: 0
|
||||
PenaltyBreakTemplateDeclaration: 0
|
||||
PenaltyExcessCharacter: 0
|
||||
PenaltyReturnTypeOnItsOwnLine: 0
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
PPIndentWidth: -1
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: false
|
||||
RemoveBracesLLVM: false
|
||||
RequiresClausePosition: OwnLine
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SortIncludes: false
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: true
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: true
|
||||
AfterOverloadedOperator: false
|
||||
AfterRequiresInClause: false
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterFunction: false
|
||||
AfterCaseLabel: false
|
||||
AfterStruct: false
|
||||
AfterClass: false
|
||||
AfterEnum: false
|
||||
AfterUnion: false
|
||||
AfterControlStatement: Never
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: true
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
BitFieldColonSpacing: Both
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
...
|
||||
|
||||
|
||||
1
.github/FUNDING.yml
vendored
@@ -1,3 +1,4 @@
|
||||
github: jonaski
|
||||
patreon: jonaskvinge
|
||||
ko_fi: jonaskvinge
|
||||
custom: https://paypal.me/jonaskvinge
|
||||
|
||||
9
.github/ISSUE_TEMPLATE.md
vendored
@@ -7,12 +7,9 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
For technical issues, questions and feature suggestions/requests please use the forum on https://forum.strawberrymusicplayer.org/
|
||||
|
||||
Check the Changelog to see if the issue is already fixed:
|
||||
https://github.com/strawberrymusicplayer/strawberry/blob/master/Changelog
|
||||
|
||||
If it's fixed, try the latest development build from: https://builds.strawberrymusicplayer.org/
|
||||
- [ ] I have checked the [FAQ](https://wiki.strawberrymusicplayer.org/wiki/FAQ) for answers.
|
||||
- [ ] I have checked the [Changelog](https://github.com/strawberrymusicplayer/strawberry/blob/master/Changelog) that the issue is not already fixed.
|
||||
- [ ] I believe this issue is a bug, and not a general technical issue, question or feature requests that can be discussed on the [forum](https://forum.strawberrymusicplayer.org/).
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
6
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
1535
.github/workflows/build.yml
vendored
Normal file
1324
.github/workflows/ccpp.yml
vendored
137
.gitignore
vendored
@@ -1,121 +1,16 @@
|
||||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# Build
|
||||
build/
|
||||
bin/
|
||||
|
||||
# CMake
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Makefile*
|
||||
Testing
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Dump files
|
||||
*.core
|
||||
*.stackdump
|
||||
|
||||
# Qt
|
||||
*build-*
|
||||
moc_*.cpp
|
||||
moc_*.h
|
||||
qrc_*.cpp
|
||||
ui_*.h
|
||||
*.moc
|
||||
*.qm
|
||||
|
||||
# QtCreator
|
||||
CMakeLists.txt.user*
|
||||
*.pro.user
|
||||
*.pro.user.*
|
||||
*creator.user*
|
||||
target_wrapper.*
|
||||
compile_commands.json
|
||||
|
||||
*.kdev4
|
||||
*.vscode
|
||||
*.code-workspace
|
||||
*.sublime-workspace
|
||||
|
||||
# Temporary files
|
||||
*~
|
||||
*.autosave
|
||||
*.orig
|
||||
*.rej
|
||||
.*.kate-swp
|
||||
.swp.*
|
||||
.*.swp
|
||||
*.flc
|
||||
|
||||
# Directory files
|
||||
.directory
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Package files
|
||||
*.spec
|
||||
*.nsi
|
||||
*.plist
|
||||
|
||||
# Stuff in dist
|
||||
maketarball.sh
|
||||
changelog
|
||||
PKGBUILD
|
||||
|
||||
# Translations
|
||||
translations.pot
|
||||
zanata.xml
|
||||
.zanata-cache/
|
||||
|
||||
# Snap
|
||||
parts/
|
||||
prime/
|
||||
stage/
|
||||
*.snap
|
||||
/snap/.snapcraft/
|
||||
/*_source.tar.bz2
|
||||
/build
|
||||
/bin
|
||||
/CMakeLists.txt.user
|
||||
/.kdev4
|
||||
/strawberry.kdev4
|
||||
/.vscode
|
||||
/.code-workspace
|
||||
/.sublime-workspace
|
||||
/.idea
|
||||
/.vs
|
||||
/out
|
||||
/CMakeSettings.json
|
||||
/dist/scripts/maketarball.sh
|
||||
/dist/unix/strawberry.spec
|
||||
/debian/changelog
|
||||
/dist/macos/Info.plist
|
||||
|
||||
4
.gitmodules
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
[submodule "3rdparty/kdsingleapplication/KDSingleApplication"]
|
||||
path = 3rdparty/kdsingleapplication/KDSingleApplication
|
||||
url = https://github.com/KDAB/KDSingleApplication.git
|
||||
branch = master
|
||||
26
3rdparty/README.md
vendored
@@ -1,25 +1,11 @@
|
||||
3rdparty libraries located in this directory
|
||||
============================================
|
||||
|
||||
singleapplication
|
||||
-----------------
|
||||
This is a small static library used by Strawberry to prevent it from starting twice per user session.
|
||||
KDSingleApplication
|
||||
-------------------
|
||||
A small library used by Strawberry to prevent it from starting twice per user session.
|
||||
If the user tries to start strawberry twice, the main window will maximize instead of starting another instance.
|
||||
If you dynamically link to your systems version, you'll need two versions, one defined as QApplication and
|
||||
one as a QCoreApplication.
|
||||
It is included here because it is not packed by distros and is also used on macOS and Windows.
|
||||
It is also used to pass command-line options through to the first instance.
|
||||
This 3rdparty copy is used only if KDSingleApplication 1.1 or higher is not found on the system.
|
||||
|
||||
URL: https://github.com/itay-grudev/SingleApplication
|
||||
|
||||
|
||||
SPMediaKeyTap
|
||||
-------------
|
||||
Used on macOS to exclusively enable strawberry to grab global media shortcuts.
|
||||
Can safely be deleted on other platforms.
|
||||
|
||||
|
||||
macdeployqt
|
||||
-----------
|
||||
A modified version of Qt's official macdeployqt utility that fixes some issues,
|
||||
this version also deploys gstreamer plugins.
|
||||
Can safely be deleted on other platforms.
|
||||
URL: https://github.com/KDAB/KDSingleApplication/
|
||||
|
||||
11
3rdparty/SPMediaKeyTap/CMakeLists.txt
vendored
@@ -1,11 +0,0 @@
|
||||
set(SPMEDIAKEY-SOURCES
|
||||
SPMediaKeyTap.m
|
||||
)
|
||||
|
||||
set(SPMEDIAKEY-HEADERS
|
||||
SPMediaKeyTap.h
|
||||
)
|
||||
|
||||
ADD_LIBRARY(SPMediaKeyTap STATIC
|
||||
${SPMEDIAKEY-SOURCES}
|
||||
)
|
||||
8
3rdparty/SPMediaKeyTap/LICENSE
vendored
@@ -1,8 +0,0 @@
|
||||
Copyright (c) 2011, Joachim Bengtsson
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Neither the name of the organization nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
12
3rdparty/SPMediaKeyTap/README.md
vendored
@@ -1,12 +0,0 @@
|
||||
SPMediaKeyTap
|
||||
=============
|
||||
|
||||
`SPMediaKeyTap` abstracts a `CGEventHook` and other nastiness in order to give you a relatively simple API to receive media key events (prev/next/playpause, on F7 to F9 on modern MacBook Pros) exclusively, without them reaching other applications like iTunes. `SPMediaKeyTap` is clever enough to resign its exclusive lock on media keys by looking for which application was active most recently: if that application is in `SPMediaKeyTap`'s whitelist, it will resign the keys. This is similar to the behavior of Apple's applications collaborating on media key handling exclusivity, but unfortunately, Apple is not exposing any APIs allowing third-parties to join in on this collaboration.
|
||||
|
||||
For now, the whitelist is just a hardcoded array in `+[SPMediaKeyTap defaultMediaKeyUserBundleIdentifiers]`. If your app starts using `SPMediaKeyTap`, please [mail me](mailto:nevyn@spotify.com) your bundle ID, and I'll include it in the canonical repository. This is a bad solution; a better solution would be to use distributed notifications to collaborate in creating this whitelist at runtime. Hopefully someone'll have the time and energy to write this soon.
|
||||
|
||||
In `Example/SPMediaKeyTapExampleAppDelegate.m` is an example of both how you use `SPMediaKeyTap`, and how you handle the semi-private `NSEvent` subtypes involved in media keys, including on how to fall back to non-event tap handling of these events.
|
||||
|
||||
`SPMediaKeyTap` and other `CGEventHook`s on the event type `NSSystemDefined` is known to interfere with each other and applications doing weird stuff with mouse input, because mouse clicks are also part of the `NSSystemDefined` category. The single issue we have had reported here at Spotify is Adobe Fireworks, in which item selection stops working with `SPMediaKeyTap` is active.
|
||||
|
||||
`SPMediaKeyTap` requires 10.5 to work, and disables itself on 10.4.
|
||||
53
3rdparty/SPMediaKeyTap/SPMediaKeyTap.h
vendored
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011, Joachim Bengtsson
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Neither the name of the organization nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <IOKit/hidsystem/ev_keymap.h>
|
||||
|
||||
// http://overooped.com/post/2593597587/mediakeys
|
||||
|
||||
#define SPSystemDefinedEventMediaKeys 8
|
||||
|
||||
@interface SPMediaKeyTap : NSObject
|
||||
|
||||
- (id)initWithDelegate:(id)delegate;
|
||||
|
||||
+ (BOOL)usesGlobalMediaKeyTap;
|
||||
- (BOOL)startWatchingMediaKeys;
|
||||
- (void)stopWatchingMediaKeys;
|
||||
- (void)handleAndReleaseMediaKeyEvent:(NSEvent *)event;
|
||||
@end
|
||||
|
||||
@interface NSObject (SPMediaKeyTapDelegate)
|
||||
- (void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
|
||||
@end
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern NSString *kIgnoreMediaKeysDefaultsKey;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
361
3rdparty/SPMediaKeyTap/SPMediaKeyTap.m
vendored
@@ -1,361 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011, Joachim Bengtsson
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Neither the name of the organization nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Copyright (c) 2010 Spotify AB
|
||||
#import "SPMediaKeyTap.h"
|
||||
|
||||
// Define to enable app list debug output
|
||||
// #define DEBUG_SPMEDIAKEY_APPLIST 1
|
||||
|
||||
NSString *kIgnoreMediaKeysDefaultsKey = @"SPIgnoreMediaKeys";
|
||||
|
||||
@interface SPMediaKeyTap () {
|
||||
CFMachPortRef _eventPort;
|
||||
CFRunLoopSourceRef _eventPortSource;
|
||||
CFRunLoopRef _tapThreadRL;
|
||||
NSThread *_tapThread;
|
||||
BOOL _shouldInterceptMediaKeyEvents;
|
||||
id _delegate;
|
||||
// The app that is frontmost in this list owns media keys
|
||||
NSMutableArray<NSRunningApplication *> *_mediaKeyAppList;
|
||||
}
|
||||
|
||||
- (BOOL)shouldInterceptMediaKeyEvents;
|
||||
- (void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting;
|
||||
- (void)startWatchingAppSwitching;
|
||||
- (void)stopWatchingAppSwitching;
|
||||
- (void)eventTapThread;
|
||||
@end
|
||||
|
||||
static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon);
|
||||
|
||||
|
||||
// Inspired by http://gist.github.com/546311
|
||||
|
||||
@implementation SPMediaKeyTap
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Setup and teardown
|
||||
|
||||
- (id)initWithDelegate:(id)delegate
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_delegate = delegate;
|
||||
[self startWatchingAppSwitching];
|
||||
_mediaKeyAppList = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self stopWatchingMediaKeys];
|
||||
[self stopWatchingAppSwitching];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)startWatchingAppSwitching
|
||||
{
|
||||
// Listen to "app switched" event, so that we don't intercept media keys if we
|
||||
// weren't the last "media key listening" app to be active
|
||||
|
||||
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
|
||||
selector:@selector(frontmostAppChanged:)
|
||||
name:NSWorkspaceDidActivateApplicationNotification
|
||||
object:nil];
|
||||
|
||||
|
||||
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
|
||||
selector:@selector(appTerminated:)
|
||||
name:NSWorkspaceDidTerminateApplicationNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)stopWatchingAppSwitching
|
||||
{
|
||||
[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (BOOL)startWatchingMediaKeys
|
||||
{
|
||||
// Prevent having multiple mediaKeys threads
|
||||
[self stopWatchingMediaKeys];
|
||||
|
||||
[self setShouldInterceptMediaKeyEvents:YES];
|
||||
|
||||
// Add an event tap to intercept the system defined media key events
|
||||
_eventPort = CGEventTapCreate(kCGSessionEventTap,
|
||||
kCGHeadInsertEventTap,
|
||||
kCGEventTapOptionDefault,
|
||||
CGEventMaskBit(NX_SYSDEFINED),
|
||||
tapEventCallback,
|
||||
(__bridge void * __nullable)(self));
|
||||
|
||||
// Can be NULL if the app has no accessibility access permission
|
||||
if (_eventPort == NULL)
|
||||
return NO;
|
||||
|
||||
_eventPortSource = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, _eventPort, 0);
|
||||
assert(_eventPortSource != NULL);
|
||||
|
||||
if (_eventPortSource == NULL)
|
||||
return NO;
|
||||
|
||||
// Let's do this in a separate thread so that a slow app doesn't lag the event tap
|
||||
_tapThread = [[NSThread alloc] initWithTarget:self
|
||||
selector:@selector(eventTapThread)
|
||||
object:nil];
|
||||
[_tapThread start];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)stopWatchingMediaKeys
|
||||
{
|
||||
// Shut down tap thread
|
||||
if(_tapThreadRL){
|
||||
CFRunLoopStop(_tapThreadRL);
|
||||
_tapThreadRL = nil;
|
||||
}
|
||||
|
||||
// Remove tap port
|
||||
if(_eventPort){
|
||||
CFMachPortInvalidate(_eventPort);
|
||||
CFRelease(_eventPort);
|
||||
_eventPort = nil;
|
||||
}
|
||||
|
||||
// Remove tap source
|
||||
if(_eventPortSource){
|
||||
CFRelease(_eventPortSource);
|
||||
_eventPortSource = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
+ (BOOL)usesGlobalMediaKeyTap
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
// breaking in gdb with a key tap inserted sometimes locks up all mouse and keyboard input forever, forcing reboot
|
||||
return NO;
|
||||
#else
|
||||
// XXX(nevyn): MediaKey event tap doesn't work on 10.4, feel free to figure out why if you have the energy.
|
||||
return
|
||||
![[NSUserDefaults standardUserDefaults] boolForKey:kIgnoreMediaKeysDefaultsKey]
|
||||
&& floor(NSAppKitVersionNumber) >= 949/*NSAppKitVersionNumber10_5*/;
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (NSArray*)mediaKeyUserBundleIdentifiers
|
||||
{
|
||||
return [NSArray arrayWithObjects:
|
||||
[[NSBundle mainBundle] bundleIdentifier], // your app
|
||||
@"com.spotify.client",
|
||||
@"com.apple.iTunes",
|
||||
@"com.apple.QuickTimePlayerX",
|
||||
@"com.apple.quicktimeplayer",
|
||||
@"com.apple.iWork.Keynote",
|
||||
@"com.apple.iPhoto",
|
||||
@"org.videolan.vlc",
|
||||
@"com.apple.Aperture",
|
||||
@"com.plexsquared.Plex",
|
||||
@"com.soundcloud.desktop",
|
||||
@"org.niltsh.MPlayerX",
|
||||
@"com.ilabs.PandorasHelper",
|
||||
@"com.mahasoftware.pandabar",
|
||||
@"com.bitcartel.pandorajam",
|
||||
@"org.clementine-player.clementine",
|
||||
@"fm.last.Last.fm",
|
||||
@"fm.last.Scrobbler",
|
||||
@"com.beatport.BeatportPro",
|
||||
@"com.Timenut.SongKey",
|
||||
@"com.macromedia.fireworks", // the tap messes up their mouse input
|
||||
@"at.justp.Theremin",
|
||||
@"ru.ya.themblsha.YandexMusic",
|
||||
@"com.jriver.MediaCenter18",
|
||||
@"com.jriver.MediaCenter19",
|
||||
@"com.jriver.MediaCenter20",
|
||||
@"co.rackit.mate",
|
||||
@"com.ttitt.b-music",
|
||||
@"com.beardedspice.BeardedSpice",
|
||||
@"com.plug.Plug",
|
||||
@"com.plug.Plug2",
|
||||
@"com.netease.163music",
|
||||
@"org.quodlibet.quodlibet",
|
||||
nil
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)shouldInterceptMediaKeyEvents
|
||||
{
|
||||
BOOL shouldIntercept = NO;
|
||||
@synchronized(self) {
|
||||
shouldIntercept = _shouldInterceptMediaKeyEvents;
|
||||
}
|
||||
return shouldIntercept;
|
||||
}
|
||||
|
||||
- (void)pauseTapOnTapThread:(NSNumber *)yeahno
|
||||
{
|
||||
CGEventTapEnable(self->_eventPort, [yeahno boolValue]);
|
||||
}
|
||||
|
||||
- (void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting
|
||||
{
|
||||
BOOL oldSetting;
|
||||
@synchronized(self) {
|
||||
oldSetting = _shouldInterceptMediaKeyEvents;
|
||||
_shouldInterceptMediaKeyEvents = newSetting;
|
||||
}
|
||||
if(_tapThreadRL && oldSetting != newSetting) {
|
||||
[self performSelector:@selector(pauseTapOnTapThread:)
|
||||
onThread:_tapThread
|
||||
withObject:@(newSetting)
|
||||
waitUntilDone:NO];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Event tap callbacks
|
||||
|
||||
// Note: method called on background thread
|
||||
|
||||
static CGEventRef tapEventCallback2(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
|
||||
{
|
||||
#pragma unused(proxy)
|
||||
SPMediaKeyTap *self = (__bridge SPMediaKeyTap *)refcon;
|
||||
|
||||
if(type == kCGEventTapDisabledByTimeout) {
|
||||
NSLog(@"Media key event tap was disabled by timeout");
|
||||
CGEventTapEnable(self->_eventPort, TRUE);
|
||||
return event;
|
||||
} else if(type == kCGEventTapDisabledByUserInput) {
|
||||
// Was disabled manually by -[pauseTapOnTapThread]
|
||||
return event;
|
||||
}
|
||||
NSEvent *nsEvent = nil;
|
||||
@try {
|
||||
nsEvent = [NSEvent eventWithCGEvent:event];
|
||||
}
|
||||
@catch (NSException * e) {
|
||||
NSLog(@"Strange CGEventType: %d: %@", type, e);
|
||||
assert(0);
|
||||
return event;
|
||||
}
|
||||
|
||||
if (type != NX_SYSDEFINED || [nsEvent subtype] != SPSystemDefinedEventMediaKeys)
|
||||
return event;
|
||||
|
||||
int keyCode = (([nsEvent data1] & 0xFFFF0000) >> 16);
|
||||
if (keyCode != NX_KEYTYPE_PLAY && keyCode != NX_KEYTYPE_FAST && keyCode != NX_KEYTYPE_REWIND && keyCode != NX_KEYTYPE_PREVIOUS && keyCode != NX_KEYTYPE_NEXT)
|
||||
return event;
|
||||
|
||||
if (![self shouldInterceptMediaKeyEvents])
|
||||
return event;
|
||||
|
||||
[self performSelectorOnMainThread:@selector(handleAndReleaseMediaKeyEvent:) withObject:nsEvent waitUntilDone:NO];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
|
||||
{
|
||||
@autoreleasepool {
|
||||
CGEventRef ret = tapEventCallback2(proxy, type, event, refcon);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleAndReleaseMediaKeyEvent:(NSEvent *)event
|
||||
{
|
||||
[_delegate mediaKeyTap:self receivedMediaKeyEvent:event];
|
||||
}
|
||||
|
||||
- (void)eventTapThread
|
||||
{
|
||||
_tapThreadRL = CFRunLoopGetCurrent();
|
||||
CFRunLoopAddSource(_tapThreadRL, _eventPortSource, kCFRunLoopCommonModes);
|
||||
CFRunLoopRun();
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Task switching callbacks
|
||||
|
||||
- (void)mediaKeyAppListChanged
|
||||
{
|
||||
#ifdef DEBUG_SPMEDIAKEY_APPLIST
|
||||
[self debugPrintAppList];
|
||||
#endif
|
||||
|
||||
if([_mediaKeyAppList count] == 0)
|
||||
return;
|
||||
|
||||
NSRunningApplication *thisApp = [NSRunningApplication currentApplication];
|
||||
NSRunningApplication *otherApp = [_mediaKeyAppList firstObject];
|
||||
|
||||
BOOL isCurrent = [thisApp isEqual:otherApp];
|
||||
|
||||
[self setShouldInterceptMediaKeyEvents:isCurrent];
|
||||
}
|
||||
|
||||
- (void)frontmostAppChanged:(NSNotification *)notification
|
||||
{
|
||||
NSRunningApplication *app = [notification.userInfo objectForKey:NSWorkspaceApplicationKey];
|
||||
if (app.bundleIdentifier == nil)
|
||||
return;
|
||||
|
||||
if (![[SPMediaKeyTap mediaKeyUserBundleIdentifiers] containsObject:app.bundleIdentifier])
|
||||
return;
|
||||
|
||||
[_mediaKeyAppList removeObject:app];
|
||||
[_mediaKeyAppList insertObject:app atIndex:0];
|
||||
[self mediaKeyAppListChanged];
|
||||
}
|
||||
|
||||
- (void)appTerminated:(NSNotification *)notification
|
||||
{
|
||||
NSRunningApplication *app = [notification.userInfo objectForKey:NSWorkspaceApplicationKey];
|
||||
[_mediaKeyAppList removeObject:app];
|
||||
|
||||
[self mediaKeyAppListChanged];
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SPMEDIAKEY_APPLIST
|
||||
- (void)debugPrintAppList
|
||||
{
|
||||
NSMutableString *list = [NSMutableString stringWithCapacity:255];
|
||||
for (NSRunningApplication *app in _mediaKeyAppList) {
|
||||
[list appendFormat:@" - %@\n", app.bundleIdentifier];
|
||||
}
|
||||
NSLog(@"List: \n%@", list);
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
||||
11
3rdparty/kdsingleapplication/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
set(SOURCES KDSingleApplication/src/kdsingleapplication.cpp KDSingleApplication/src/kdsingleapplication_localsocket.cpp)
|
||||
set(HEADERS KDSingleApplication/src/kdsingleapplication.h KDSingleApplication/src/kdsingleapplication_localsocket_p.h)
|
||||
qt_wrap_cpp(MOC ${HEADERS})
|
||||
add_library(kdsingleapplication STATIC ${SOURCES} ${MOC})
|
||||
if(NOT MSVC)
|
||||
target_compile_options(kdsingleapplication PRIVATE -Wno-missing-declarations)
|
||||
endif()
|
||||
target_compile_definitions(kdsingleapplication PRIVATE -DKDSINGLEAPPLICATION_STATIC_BUILD)
|
||||
target_include_directories(kdsingleapplication PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(kdsingleapplication PUBLIC Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Network)
|
||||
1
3rdparty/kdsingleapplication/KDSingleApplication
vendored
Submodule
7
3rdparty/macdeployqt/CMakeLists.txt
vendored
@@ -1,7 +0,0 @@
|
||||
add_executable(macdeployqt main.cpp shared.cpp)
|
||||
target_link_libraries(macdeployqt PRIVATE
|
||||
"-framework AppKit"
|
||||
${QtCore_LIBRARIES}
|
||||
)
|
||||
|
||||
#execute_process(COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/macdeployqt ${CMAKE_BINARY_DIR})
|
||||
286
3rdparty/macdeployqt/main.cpp
vendored
@@ -1,286 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the tools applications of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#undef QT_NO_DEBUG_OUTPUT
|
||||
#undef QT_NO_WARNING_OUTPUT
|
||||
#undef QT_NO_INFO_OUTPUT
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QLibraryInfo>
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
QString appBundlePath;
|
||||
if (argc > 1)
|
||||
appBundlePath = QString::fromLocal8Bit(argv[1]);
|
||||
|
||||
if (argc < 2 || appBundlePath.startsWith("-")) {
|
||||
qDebug() << "Usage: macdeployqt app-bundle [options]";
|
||||
qDebug() << "";
|
||||
qDebug() << "Options:";
|
||||
qDebug() << " -verbose=<0-3> : 0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug";
|
||||
qDebug() << " -no-plugins : Skip plugin deployment";
|
||||
qDebug() << " -dmg : Create a .dmg disk image";
|
||||
qDebug() << " -no-strip : Don't run 'strip' on the binaries";
|
||||
qDebug() << " -use-debug-libs : Deploy with debug versions of frameworks and plugins (implies -no-strip)";
|
||||
qDebug() << " -executable=<path> : Let the given executable use the deployed frameworks too";
|
||||
qDebug() << " -qmldir=<path> : Scan for QML imports in the given path";
|
||||
qDebug() << " -qmlimport=<path> : Add the given path to the QML module search locations";
|
||||
qDebug() << " -always-overwrite : Copy files even if the target file exists";
|
||||
qDebug() << " -codesign=<ident> : Run codesign with the given identity on all executables";
|
||||
qDebug() << " -hardened-runtime : Enable Hardened Runtime when code signing";
|
||||
qDebug() << " -timestamp : Include a secure timestamp when code signing (requires internet connection)";
|
||||
qDebug() << " -sign-for-notarization=<ident>: Activate the necessary options for notarization (requires internet connection)";
|
||||
qDebug() << " -appstore-compliant : Skip deployment of components that use private API";
|
||||
qDebug() << " -libpath=<path> : Add the given path to the library search path";
|
||||
qDebug() << " -fs=<filesystem> : Set the filesystem used for the .dmg disk image (defaults to HFS+)";
|
||||
qDebug() << "";
|
||||
qDebug() << "macdeployqt takes an application bundle as input and makes it";
|
||||
qDebug() << "self-contained by copying in the Qt frameworks and plugins that";
|
||||
qDebug() << "the application uses.";
|
||||
qDebug() << "";
|
||||
qDebug() << "Plugins related to a framework are copied in with the";
|
||||
qDebug() << "framework. The accessibility, image formats, and text codec";
|
||||
qDebug() << "plugins are always copied, unless \"-no-plugins\" is specified.";
|
||||
qDebug() << "";
|
||||
qDebug() << "Qt plugins may use private API and will cause the app to be";
|
||||
qDebug() << "rejected from the Mac App store. MacDeployQt will print a warning";
|
||||
qDebug() << "when known incompatible plugins are deployed. Use -appstore-compliant ";
|
||||
qDebug() << "to skip these plugins. Currently two SQL plugins are known to";
|
||||
qDebug() << "be incompatible: qsqlodbc and qsqlpsql.";
|
||||
qDebug() << "";
|
||||
qDebug() << "See the \"Deploying Applications on OS X\" topic in the";
|
||||
qDebug() << "documentation for more information about deployment on OS X.";
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
appBundlePath = QDir::cleanPath(appBundlePath);
|
||||
|
||||
if (QDir().exists(appBundlePath) == false) {
|
||||
qDebug() << "Error: Could not find app bundle" << appBundlePath;
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool plugins = true;
|
||||
bool dmg = false;
|
||||
QByteArray filesystem("HFS+");
|
||||
bool useDebugLibs = false;
|
||||
extern bool runStripEnabled;
|
||||
extern bool alwaysOwerwriteEnabled;
|
||||
extern QStringList librarySearchPath;
|
||||
QStringList additionalExecutables;
|
||||
bool qmldirArgumentUsed = false;
|
||||
QStringList qmlDirs;
|
||||
QStringList qmlImportPaths;
|
||||
extern bool runCodesign;
|
||||
extern QString codesignIdentiy;
|
||||
extern bool hardenedRuntime;
|
||||
extern bool appstoreCompliant;
|
||||
extern bool deployFramework;
|
||||
extern bool secureTimestamp;
|
||||
|
||||
for (int i = 2; i < argc; ++i) {
|
||||
QByteArray argument = QByteArray(argv[i]);
|
||||
if (argument == QByteArray("-no-plugins")) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
plugins = false;
|
||||
} else if (argument == QByteArray("-dmg")) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
dmg = true;
|
||||
} else if (argument == QByteArray("-no-strip")) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
runStripEnabled = false;
|
||||
} else if (argument == QByteArray("-use-debug-libs")) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
useDebugLibs = true;
|
||||
runStripEnabled = false;
|
||||
} else if (argument.startsWith(QByteArray("-verbose"))) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
int index = argument.indexOf("=");
|
||||
bool ok = false;
|
||||
int number = argument.mid(index+1).toInt(&ok);
|
||||
if (!ok)
|
||||
LogError() << "Could not parse verbose level";
|
||||
else
|
||||
logLevel = number;
|
||||
} else if (argument.startsWith(QByteArray("-executable"))) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
int index = argument.indexOf('=');
|
||||
if (index == -1)
|
||||
LogError() << "Missing executable path";
|
||||
else
|
||||
additionalExecutables << argument.mid(index+1);
|
||||
} else if (argument.startsWith(QByteArray("-qmldir"))) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
qmldirArgumentUsed = true;
|
||||
int index = argument.indexOf('=');
|
||||
if (index == -1)
|
||||
LogError() << "Missing qml directory path";
|
||||
else
|
||||
qmlDirs << argument.mid(index+1);
|
||||
} else if (argument.startsWith(QByteArray("-qmlimport"))) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
int index = argument.indexOf('=');
|
||||
if (index == -1)
|
||||
LogError() << "Missing qml import path";
|
||||
else
|
||||
qmlImportPaths << argument.mid(index+1);
|
||||
} else if (argument.startsWith(QByteArray("-libpath"))) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
int index = argument.indexOf('=');
|
||||
if (index == -1)
|
||||
LogError() << "Missing library search path";
|
||||
else
|
||||
librarySearchPath << argument.mid(index+1);
|
||||
} else if (argument == QByteArray("-always-overwrite")) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
alwaysOwerwriteEnabled = true;
|
||||
} else if (argument.startsWith(QByteArray("-codesign"))) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
int index = argument.indexOf("=");
|
||||
if (index < 0 || index >= argument.size()) {
|
||||
LogError() << "Missing code signing identity";
|
||||
} else {
|
||||
runCodesign = true;
|
||||
codesignIdentiy = argument.mid(index+1);
|
||||
}
|
||||
} else if (argument.startsWith(QByteArray("-sign-for-notarization"))) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
int index = argument.indexOf("=");
|
||||
if (index < 0 || index >= argument.size()) {
|
||||
LogError() << "Missing code signing identity";
|
||||
} else {
|
||||
runCodesign = true;
|
||||
hardenedRuntime = true;
|
||||
secureTimestamp = true;
|
||||
codesignIdentiy = argument.mid(index+1);
|
||||
}
|
||||
} else if (argument.startsWith(QByteArray("-hardened-runtime"))) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
hardenedRuntime = true;
|
||||
} else if (argument.startsWith(QByteArray("-timestamp"))) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
secureTimestamp = true;
|
||||
} else if (argument == QByteArray("-appstore-compliant")) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
appstoreCompliant = true;
|
||||
|
||||
// Undocumented option, may not work as intended
|
||||
} else if (argument == QByteArray("-deploy-framework")) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
deployFramework = true;
|
||||
|
||||
} else if (argument.startsWith(QByteArray("-fs"))) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
int index = argument.indexOf('=');
|
||||
if (index == -1)
|
||||
LogError() << "Missing filesystem type";
|
||||
else
|
||||
filesystem = argument.mid(index+1);
|
||||
} else if (argument.startsWith("-")) {
|
||||
LogError() << "Unknown argument" << argument << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
DeploymentInfo deploymentInfo = deployQtFrameworks(appBundlePath, additionalExecutables, useDebugLibs);
|
||||
|
||||
if (deploymentInfo.isDebug)
|
||||
useDebugLibs = true;
|
||||
|
||||
if (deployFramework && deploymentInfo.isFramework)
|
||||
fixupFramework(appBundlePath);
|
||||
|
||||
// Convenience: Look for .qml files in the current directory if no -qmldir specified.
|
||||
if (qmlDirs.isEmpty()) {
|
||||
QDir dir;
|
||||
if (!dir.entryList(QStringList() << QStringLiteral("*.qml")).isEmpty()) {
|
||||
qmlDirs += QStringLiteral(".");
|
||||
}
|
||||
}
|
||||
|
||||
if (!qmlDirs.isEmpty()) {
|
||||
bool ok = deployQmlImports(appBundlePath, deploymentInfo, qmlDirs, qmlImportPaths);
|
||||
if (!ok && qmldirArgumentUsed)
|
||||
return 1; // exit if the user explicitly asked for qml import deployment
|
||||
|
||||
// Update deploymentInfo.deployedFrameworks - the QML imports
|
||||
// may have brought in extra frameworks as dependencies.
|
||||
deploymentInfo.deployedFrameworks += findAppFrameworkNames(appBundlePath);
|
||||
deploymentInfo.deployedFrameworks =
|
||||
QSet<QString>(deploymentInfo.deployedFrameworks.begin(),
|
||||
deploymentInfo.deployedFrameworks.end()).values();
|
||||
}
|
||||
|
||||
// Handle plugins
|
||||
if (plugins) {
|
||||
// Set the plugins search directory
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
deploymentInfo.pluginPath = QLibraryInfo::path(QLibraryInfo::PluginsPath);
|
||||
#else
|
||||
deploymentInfo.pluginPath = QLibraryInfo::location(QLibraryInfo::PluginsPath);
|
||||
#endif
|
||||
// Sanity checks
|
||||
if (deploymentInfo.pluginPath.isEmpty()) {
|
||||
LogError() << "Missing Qt plugins path\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!QDir(deploymentInfo.pluginPath).exists()) {
|
||||
LogError() << "Plugins path does not exist" << deploymentInfo.pluginPath << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Deploy plugins
|
||||
Q_ASSERT(!deploymentInfo.pluginPath.isEmpty());
|
||||
if (!deploymentInfo.pluginPath.isEmpty()) {
|
||||
LogNormal();
|
||||
deployPlugins(appBundlePath, deploymentInfo, useDebugLibs);
|
||||
createQtConf(appBundlePath);
|
||||
}
|
||||
}
|
||||
|
||||
if (runStripEnabled)
|
||||
stripAppBinary(appBundlePath);
|
||||
|
||||
if (runCodesign)
|
||||
codesign(codesignIdentiy, appBundlePath);
|
||||
|
||||
if (dmg) {
|
||||
LogNormal();
|
||||
createDiskImage(appBundlePath, filesystem);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
1777
3rdparty/macdeployqt/shared.cpp
vendored
141
3rdparty/macdeployqt/shared.h
vendored
@@ -1,141 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the tools applications of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
#ifndef MAC_DEPLOMYMENT_SHARED_H
|
||||
#define MAC_DEPLOMYMENT_SHARED_H
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QDebug>
|
||||
#include <QSet>
|
||||
#include <QVersionNumber>
|
||||
|
||||
extern int logLevel;
|
||||
#define LogError() if (logLevel < 0) {} else qDebug() << "ERROR:"
|
||||
#define LogWarning() if (logLevel < 1) {} else qDebug() << "WARNING:"
|
||||
#define LogNormal() if (logLevel < 2) {} else qDebug() << "Log:"
|
||||
#define LogDebug() if (logLevel < 3) {} else qDebug() << "Log:"
|
||||
|
||||
extern bool runStripEnabled;
|
||||
|
||||
class FrameworkInfo
|
||||
{
|
||||
public:
|
||||
bool isDylib;
|
||||
QString frameworkDirectory;
|
||||
QString frameworkName;
|
||||
QString frameworkPath;
|
||||
QString binaryDirectory;
|
||||
QString binaryName;
|
||||
QString binaryPath;
|
||||
QString rpathUsed;
|
||||
QString version;
|
||||
QString installName;
|
||||
QString deployedInstallName;
|
||||
QString sourceFilePath;
|
||||
QString frameworkDestinationDirectory;
|
||||
QString binaryDestinationDirectory;
|
||||
|
||||
bool isDebugLibrary() const
|
||||
{
|
||||
return binaryName.endsWith(QStringLiteral("_debug"));
|
||||
}
|
||||
};
|
||||
|
||||
class DylibInfo
|
||||
{
|
||||
public:
|
||||
QString binaryPath;
|
||||
QVersionNumber currentVersion;
|
||||
QVersionNumber compatibilityVersion;
|
||||
};
|
||||
|
||||
class OtoolInfo
|
||||
{
|
||||
public:
|
||||
QString installName;
|
||||
QString binaryPath;
|
||||
QVersionNumber currentVersion;
|
||||
QVersionNumber compatibilityVersion;
|
||||
QList<DylibInfo> dependencies;
|
||||
};
|
||||
|
||||
bool operator==(const FrameworkInfo &a, const FrameworkInfo &b);
|
||||
QDebug operator<<(QDebug debug, const FrameworkInfo &info);
|
||||
|
||||
class ApplicationBundleInfo
|
||||
{
|
||||
public:
|
||||
QString path;
|
||||
QString binaryPath;
|
||||
QStringList libraryPaths;
|
||||
};
|
||||
|
||||
class DeploymentInfo
|
||||
{
|
||||
public:
|
||||
QString qtPath;
|
||||
QString pluginPath;
|
||||
QStringList deployedFrameworks;
|
||||
QList<QString> rpathsUsed;
|
||||
bool useLoaderPath;
|
||||
bool isFramework;
|
||||
bool isDebug;
|
||||
|
||||
bool containsModule(const QString &module, const QString &libInFix) const;
|
||||
};
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info);
|
||||
|
||||
OtoolInfo findDependencyInfo(const QString &binaryPath);
|
||||
FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs);
|
||||
QString findAppBinary(const QString &appBundlePath);
|
||||
QList<FrameworkInfo> getQtFrameworks(const QString &path, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs);
|
||||
QList<FrameworkInfo> getQtFrameworks(const QStringList &otoolLines, const QString &appBundlePath, const QList<QString> &rpaths, bool useDebugLibs);
|
||||
QString copyFramework(const FrameworkInfo &framework, const QString path);
|
||||
DeploymentInfo deployQtFrameworks(const QString &appBundlePath, const QStringList &additionalExecutables, bool useDebugLibs);
|
||||
DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks,const QString &bundlePath, const QStringList &binaryPaths, bool useDebugLibs, bool useLoaderPath);
|
||||
void createQtConf(const QString &appBundlePath);
|
||||
void deployPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo, bool useDebugLibs);
|
||||
bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInfo, QStringList &qmlDirs, QStringList &qmlImportPaths);
|
||||
void changeIdentification(const QString &id, const QString &binaryPath);
|
||||
void changeInstallName(const QString &oldName, const QString &newName, const QString &binaryPath);
|
||||
void runStrip(const QString &binaryPath);
|
||||
void stripAppBinary(const QString &bundlePath);
|
||||
QString findAppBinary(const QString &appBundlePath);
|
||||
QStringList findAppFrameworkNames(const QString &appBundlePath);
|
||||
QStringList findAppFrameworkPaths(const QString &appBundlePath);
|
||||
void codesignFile(const QString &identity, const QString &filePath);
|
||||
QSet<QString> codesignBundle(const QString &identity,
|
||||
const QString &appBundlePath,
|
||||
QList<QString> additionalBinariesContainingRpaths);
|
||||
void codesign(const QString &identity, const QString &appBundlePath);
|
||||
void createDiskImage(const QString &appBundlePath, const QString &filesystemType);
|
||||
void fixupFramework(const QString &appBundlePath);
|
||||
|
||||
|
||||
#endif
|
||||
38
3rdparty/singleapplication/CMakeLists.txt
vendored
@@ -1,38 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckFunctionExists)
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER 3.0)
|
||||
check_function_exists(geteuid HAVE_GETEUID)
|
||||
check_function_exists(getpwuid HAVE_GETPWUID)
|
||||
endif()
|
||||
|
||||
set(SINGLEAPP-SOURCES singleapplication.cpp singleapplication_p.cpp)
|
||||
set(SINGLEAPP-MOC-HEADERS singleapplication.h singleapplication_p.h)
|
||||
qt_wrap_cpp(SINGLEAPP-SOURCES-MOC ${SINGLEAPP-MOC-HEADERS})
|
||||
add_library(singleapplication STATIC ${SINGLEAPP-SOURCES} ${SINGLEAPP-SOURCES-MOC})
|
||||
target_include_directories(singleapplication PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
target_link_libraries(singleapplication PRIVATE
|
||||
${QtCore_LIBRARIES}
|
||||
${QtWidgets_LIBRARIES}
|
||||
${QtNetwork_LIBRARIES}
|
||||
)
|
||||
|
||||
set(SINGLECOREAPP-SOURCES singlecoreapplication.cpp singlecoreapplication_p.cpp)
|
||||
set(SINGLECOREAPP-MOC-HEADERS singlecoreapplication.h singlecoreapplication_p.h)
|
||||
qt_wrap_cpp(SINGLECOREAPP-SOURCES-MOC ${SINGLECOREAPP-MOC-HEADERS})
|
||||
add_library(singlecoreapplication STATIC ${SINGLECOREAPP-SOURCES} ${SINGLECOREAPP-SOURCES-MOC})
|
||||
target_include_directories(singlecoreapplication PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
target_link_libraries(singlecoreapplication PRIVATE
|
||||
${QtCore_LIBRARIES}
|
||||
${QtNetwork_LIBRARIES}
|
||||
)
|
||||
|
||||
configure_file(config.h.in "${CMAKE_CURRENT_BINARY_DIR}/config.h")
|
||||
265
3rdparty/singleapplication/README.md
vendored
@@ -1,265 +0,0 @@
|
||||
SingleApplication
|
||||
=================
|
||||
|
||||
This is a replacement of the QtSingleApplication for `Qt5`.
|
||||
|
||||
Keeps the Primary Instance of your Application and kills each subsequent
|
||||
instances. It can (if enabled) spawn secondary (non-related to the primary)
|
||||
instances and can send data to the primary instance from secondary instances.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
The `SingleApplication` class inherits from whatever `Q[Core|Gui]Application`
|
||||
class you specify via the `QAPPLICATION_CLASS` macro (`QCoreApplication` is the
|
||||
default). Further usage is similar to the use of the `Q[Core|Gui]Application`
|
||||
classes.
|
||||
|
||||
The library sets up a `QLocalServer` and a `QSharedMemory` block. The first
|
||||
instance of your Application is your Primary Instance. It would check if the
|
||||
shared memory block exists and if not it will start a `QLocalServer` and listen
|
||||
for connections. Each subsequent instance of your application would check if the
|
||||
shared memory block exists and if it does, it will connect to the QLocalServer
|
||||
to notify the primary instance that a new instance had been started, after which
|
||||
it would terminate with status code `0`. In the Primary Instance
|
||||
`SingleApplication` would emit the `instanceStarted()` signal upon detecting
|
||||
that a new instance had been started.
|
||||
|
||||
The library uses `stdlib` to terminate the program with the `exit()` function.
|
||||
|
||||
You can use the library as if you use any other `QCoreApplication` derived
|
||||
class:
|
||||
|
||||
```cpp
|
||||
#include <QApplication>
|
||||
#include <SingleApplication.h>
|
||||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
SingleApplication app( argc, argv );
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
```
|
||||
|
||||
To include the library files I would recommend that you add it as a git
|
||||
submodule to your project and include it's contents with a `.pri` file. Here is
|
||||
how:
|
||||
|
||||
```bash
|
||||
git submodule add git@github.com:itay-grudev/SingleApplication.git singleapplication
|
||||
```
|
||||
|
||||
Then include the `singleapplication.pri` file in your `.pro` project file. Also
|
||||
don't forget to specify which `QCoreApplication` class your app is using if it
|
||||
is not `QCoreApplication`.
|
||||
|
||||
```qmake
|
||||
include(singleapplication/singleapplication.pri)
|
||||
DEFINES += QAPPLICATION_CLASS=QApplication
|
||||
```
|
||||
|
||||
The `Instance Started` signal
|
||||
------------------------
|
||||
|
||||
The SingleApplication class implements a `instanceStarted()` signal. You can
|
||||
bind to that signal to raise your application's window when a new instance had
|
||||
been started, for example.
|
||||
|
||||
```cpp
|
||||
// window is a QWindow instance
|
||||
QObject::connect(
|
||||
&app,
|
||||
&SingleApplication::instanceStarted,
|
||||
&window,
|
||||
&QWindow::raise
|
||||
);
|
||||
```
|
||||
|
||||
Using `SingleApplication::instance()` is a neat way to get the
|
||||
`SingleApplication` instance for binding to it's signals anywhere in your
|
||||
program.
|
||||
|
||||
__Note:__ On Windows the ability to bring the application windows to the
|
||||
foreground is restricted. See [Windows specific implementations](Windows.md)
|
||||
for a workaround and an example implementation.
|
||||
|
||||
|
||||
Secondary Instances
|
||||
-------------------
|
||||
|
||||
If you want to be able to launch additional Secondary Instances (not related to
|
||||
your Primary Instance) you have to enable that with the third parameter of the
|
||||
`SingleApplication` constructor. The default is `false` meaning no Secondary
|
||||
Instances. Here is an example of how you would start a Secondary Instance send
|
||||
a message with the command line arguments to the primary instance and then shut
|
||||
down.
|
||||
|
||||
```cpp
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
SingleApplication app( argc, argv, true );
|
||||
|
||||
if( app.isSecondary() ) {
|
||||
app.sendMessage( app.arguments().join(' ')).toUtf8() );
|
||||
app.exit( 0 );
|
||||
}
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
```
|
||||
|
||||
*__Note:__ A secondary instance won't cause the emission of the
|
||||
`instanceStarted()` signal by default. See `SingleApplication::Mode` for more
|
||||
details.*
|
||||
|
||||
You can check whether your instance is a primary or secondary with the following
|
||||
methods:
|
||||
|
||||
```cpp
|
||||
app.isPrimary();
|
||||
// or
|
||||
app.isSecondary();
|
||||
```
|
||||
|
||||
*__Note:__ If your Primary Instance is terminated a newly launched instance
|
||||
will replace the Primary one even if the Secondary flag has been set.*
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
### Members
|
||||
|
||||
```cpp
|
||||
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100 )
|
||||
```
|
||||
|
||||
Depending on whether `allowSecondary` is set, this constructor may terminate
|
||||
your app if there is already a primary instance running. Additional `Options`
|
||||
can be specified to set whether the SingleApplication block should work
|
||||
user-wide or system-wide. Additionally the `Mode::SecondaryNotification` may be
|
||||
used to notify the primary instance whenever a secondary instance had been
|
||||
started (disabled by default). `timeout` specifies the maximum time in
|
||||
milliseconds to wait for blocking operations.
|
||||
|
||||
*__Note:__ `argc` and `argv` may be changed as Qt removes arguments that it
|
||||
recognizes.*
|
||||
|
||||
*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary
|
||||
and the secondary instance.*
|
||||
|
||||
*__Note:__ Operating system can restrict the shared memory blocks to the same
|
||||
user, in which case the User/System modes will have no effect and the block will
|
||||
be user wide.*
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
bool SingleApplication::sendMessage( QByteArray message, int timeout = 100 )
|
||||
```
|
||||
|
||||
Sends `message` to the Primary Instance. Uses `timeout` as a the maximum timeout
|
||||
in milliseconds for blocking functions
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
bool SingleApplication::isPrimary()
|
||||
```
|
||||
|
||||
Returns if the instance is the primary instance.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
bool SingleApplication::isSecondary()
|
||||
```
|
||||
Returns if the instance is a secondary instance.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
quint32 SingleApplication::instanceId()
|
||||
```
|
||||
|
||||
Returns a unique identifier for the current instance.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
qint64 SingleApplication::primaryPid()
|
||||
```
|
||||
|
||||
Returns the process ID (PID) of the primary instance.
|
||||
|
||||
### Signals
|
||||
|
||||
```cpp
|
||||
void SingleApplication::instanceStarted()
|
||||
```
|
||||
|
||||
Triggered whenever a new instance had been started, except for secondary
|
||||
instances if the `Mode::SecondaryNotification` flag is not specified.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
void SingleApplication::receivedMessage( quint32 instanceId, QByteArray message )
|
||||
```
|
||||
|
||||
Triggered whenever there is a message received from a secondary instance.
|
||||
|
||||
---
|
||||
|
||||
### Flags
|
||||
|
||||
```cpp
|
||||
enum SingleApplication::Mode
|
||||
```
|
||||
|
||||
* `Mode::User` - The SingleApplication block should apply user wide. This adds
|
||||
user specific data to the key used for the shared memory and server name.
|
||||
This is the default functionality.
|
||||
* `Mode::System` – The SingleApplication block applies system-wide.
|
||||
* `Mode::SecondaryNotification` – Whether to trigger `instanceStarted()` even
|
||||
whenever secondary instances are started.
|
||||
* `Mode::ExcludeAppPath` – Excludes the application path from the server name
|
||||
(and memory block) hash.
|
||||
* `Mode::ExcludeAppVersion` – Excludes the application version from the server
|
||||
name (and memory block) hash.
|
||||
|
||||
*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary
|
||||
and the secondary instance.*
|
||||
|
||||
*__Note:__ Operating system can restrict the shared memory blocks to the same
|
||||
user, in which case the User/System modes will have no effect and the block will
|
||||
be user wide.*
|
||||
|
||||
---
|
||||
|
||||
Versioning
|
||||
----------
|
||||
|
||||
Each major version introduces either very significant changes or is not
|
||||
backwards compatible with the previous version. Minor versions only add
|
||||
additional features, bug fixes or performance improvements and are backwards
|
||||
compatible with the previous release. See [`CHANGELOG.md`](CHANGELOG.md) for
|
||||
more details.
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
The library is implemented with a QSharedMemory block which is thread safe and
|
||||
guarantees a race condition will not occur. It also uses a QLocalSocket to
|
||||
notify the main process that a new instance had been spawned and thus invoke the
|
||||
`instanceStarted()` signal and for messaging the primary instance.
|
||||
|
||||
Additionally the library can recover from being forcefully killed on *nix
|
||||
systems and will reset the memory block given that there are no other
|
||||
instances running.
|
||||
|
||||
License
|
||||
-------
|
||||
This library and it's supporting documentation are released under
|
||||
`The MIT License (MIT)` with the exception of the Qt calculator examples which
|
||||
is distributed under the BSD license.
|
||||
2
3rdparty/singleapplication/config.h.in
vendored
@@ -1,2 +0,0 @@
|
||||
#cmakedefine HAVE_GETEUID
|
||||
#cmakedefine HAVE_GETPWUID
|
||||
270
3rdparty/singleapplication/singleapplication.cpp
vendored
@@ -1,270 +0,0 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) Itay Grudev 2015 - 2020
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//
|
||||
// W A R N I N G !!!
|
||||
// -----------------
|
||||
//
|
||||
// This is a modified version of SingleApplication,
|
||||
// The original version is at:
|
||||
//
|
||||
// https://github.com/itay-grudev/SingleApplication
|
||||
//
|
||||
//
|
||||
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QApplication>
|
||||
#include <QThread>
|
||||
#include <QSharedMemory>
|
||||
#include <QLocalSocket>
|
||||
#include <QByteArray>
|
||||
#include <QElapsedTimer>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "singleapplication.h"
|
||||
#include "singleapplication_p.h"
|
||||
|
||||
/**
|
||||
* @brief Constructor. Checks and fires up LocalServer or closes the program if another instance already exists
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param allowSecondary Whether to enable secondary instance support
|
||||
* @param options Optional flags to toggle specific behaviour
|
||||
* @param timeout Maximum time blocking functions are allowed during app load
|
||||
*/
|
||||
SingleApplication::SingleApplication(int &argc, char *argv[], bool allowSecondary, Options options, int timeout)
|
||||
: app_t(argc, argv),
|
||||
d_ptr(new SingleApplicationPrivate(this)) {
|
||||
|
||||
Q_D(SingleApplication);
|
||||
|
||||
// Store the current mode of the program
|
||||
d->options_ = options;
|
||||
|
||||
// Generating an application ID used for identifying the shared memory block and QLocalServer
|
||||
d->genBlockServerName();
|
||||
|
||||
// To mitigate QSharedMemory issues with large amount of processes attempting to attach at the same time
|
||||
d->randomSleep();
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
// By explicitly attaching it and then deleting it we make sure that the memory is deleted even after the process has crashed on Unix.
|
||||
d->memory_ = new QSharedMemory(d->blockServerName_);
|
||||
d->memory_->attach();
|
||||
delete d->memory_;
|
||||
#endif
|
||||
|
||||
// Guarantee thread safe behaviour with a shared memory block.
|
||||
d->memory_ = new QSharedMemory(d->blockServerName_);
|
||||
|
||||
// Create a shared memory block
|
||||
if (d->memory_->create(sizeof(InstancesInfo))) {
|
||||
// Initialize the shared memory block
|
||||
if (!d->memory_->lock()) {
|
||||
qCritical() << "SingleApplication: Unable to lock memory block after create.";
|
||||
abortSafely();
|
||||
}
|
||||
d->initializeMemoryBlock();
|
||||
}
|
||||
else {
|
||||
if (d->memory_->error() == QSharedMemory::AlreadyExists) {
|
||||
// Attempt to attach to the memory segment
|
||||
if (!d->memory_->attach()) {
|
||||
qCritical() << "SingleApplication: Unable to attach to shared memory block.";
|
||||
abortSafely();
|
||||
}
|
||||
if (!d->memory_->lock()) {
|
||||
qCritical() << "SingleApplication: Unable to lock memory block after attach.";
|
||||
abortSafely();
|
||||
}
|
||||
}
|
||||
else {
|
||||
qCritical() << "SingleApplication: Unable to create block.";
|
||||
abortSafely();
|
||||
}
|
||||
}
|
||||
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(d->memory_->data());
|
||||
QElapsedTimer time;
|
||||
time.start();
|
||||
|
||||
// Make sure the shared memory block is initialised and in consistent state
|
||||
forever {
|
||||
// If the shared memory block's checksum is valid continue
|
||||
if (d->blockChecksum() == inst->checksum) break;
|
||||
|
||||
// If more than 5s have elapsed, assume the primary instance crashed and assume it's position
|
||||
if (time.elapsed() > 5000) {
|
||||
qWarning() << "SingleApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure.";
|
||||
d->initializeMemoryBlock();
|
||||
}
|
||||
|
||||
// Otherwise wait for a random period and try again.
|
||||
// The random sleep here limits the probability of a collision between two racing apps and allows the app to initialise faster
|
||||
if (!d->memory_->unlock()) {
|
||||
qDebug() << "SingleApplication: Unable to unlock memory for random wait.";
|
||||
qDebug() << d->memory_->errorString();
|
||||
}
|
||||
d->randomSleep();
|
||||
if (!d->memory_->lock()) {
|
||||
qCritical() << "SingleApplication: Unable to lock memory after random wait.";
|
||||
abortSafely();
|
||||
}
|
||||
}
|
||||
|
||||
if (!inst->primary) {
|
||||
d->startPrimary();
|
||||
if (!d->memory_->unlock()) {
|
||||
qDebug() << "SingleApplication: Unable to unlock memory after primary start.";
|
||||
qDebug() << d->memory_->errorString();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if another instance can be started
|
||||
if (allowSecondary) {
|
||||
d->startSecondary();
|
||||
if (d->options_ & Mode::SecondaryNotification) {
|
||||
d->connectToPrimary(timeout, SingleApplicationPrivate::SecondaryInstance);
|
||||
}
|
||||
if (!d->memory_->unlock()) {
|
||||
qDebug() << "SingleApplication: Unable to unlock memory after secondary start.";
|
||||
qDebug() << d->memory_->errorString();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!d->memory_->unlock()) {
|
||||
qDebug() << "SingleApplication: Unable to unlock memory at end of execution.";
|
||||
qDebug() << d->memory_->errorString();
|
||||
}
|
||||
|
||||
d->connectToPrimary(timeout, SingleApplicationPrivate::NewInstance);
|
||||
|
||||
delete d;
|
||||
|
||||
::exit(EXIT_SUCCESS);
|
||||
|
||||
}
|
||||
|
||||
SingleApplication::~SingleApplication() {
|
||||
Q_D(SingleApplication);
|
||||
delete d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current application instance is primary.
|
||||
* @return Returns true if the instance is primary, false otherwise.
|
||||
*/
|
||||
bool SingleApplication::isPrimary() {
|
||||
Q_D(SingleApplication);
|
||||
return d->server_ != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current application instance is secondary.
|
||||
* @return Returns true if the instance is secondary, false otherwise.
|
||||
*/
|
||||
bool SingleApplication::isSecondary() {
|
||||
Q_D(SingleApplication);
|
||||
return d->server_ == nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to identify an instance by returning unique consecutive instance ids.
|
||||
* It is reset when the first (primary) instance of your app starts and only incremented afterwards.
|
||||
* @return Returns a unique instance id.
|
||||
*/
|
||||
quint32 SingleApplication::instanceId() {
|
||||
Q_D(SingleApplication);
|
||||
return d->instanceNumber_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the OS PID (Process Identifier) of the process running the primary instance.
|
||||
* Especially useful when SingleApplication is coupled with OS. specific APIs.
|
||||
* @return Returns the primary instance PID.
|
||||
*/
|
||||
qint64 SingleApplication::primaryPid() {
|
||||
Q_D(SingleApplication);
|
||||
return d->primaryPid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the username the primary instance is running as.
|
||||
* @return Returns the username the primary instance is running as.
|
||||
*/
|
||||
QString SingleApplication::primaryUser() {
|
||||
Q_D(SingleApplication);
|
||||
return d->primaryUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the username the current instance is running as.
|
||||
* @return Returns the username the current instance is running as.
|
||||
*/
|
||||
QString SingleApplication::currentUser() {
|
||||
Q_D(SingleApplication);
|
||||
return d->getUsername();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends message to the Primary Instance.
|
||||
* @param message The message to send.
|
||||
* @param timeout the maximum timeout in milliseconds for blocking functions.
|
||||
* @return true if the message was sent successfully, false otherwise.
|
||||
*/
|
||||
bool SingleApplication::sendMessage(const QByteArray &message, const int timeout) {
|
||||
|
||||
Q_D(SingleApplication);
|
||||
|
||||
// Nobody to connect to
|
||||
if (isPrimary()) return false;
|
||||
|
||||
// Make sure the socket is connected
|
||||
if (!d->connectToPrimary(timeout, SingleApplicationPrivate::Reconnect)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
d->socket_->write(message);
|
||||
const bool dataWritten = d->socket_->waitForBytesWritten(timeout);
|
||||
d->socket_->flush();
|
||||
return dataWritten;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the shared memory block and exits with a failure.
|
||||
* This function halts program execution.
|
||||
*/
|
||||
void SingleApplication::abortSafely() {
|
||||
|
||||
Q_D(SingleApplication);
|
||||
|
||||
qCritical() << "SingleApplication: " << d->memory_->error() << d->memory_->errorString();
|
||||
delete d;
|
||||
::exit(EXIT_FAILURE);
|
||||
|
||||
}
|
||||
153
3rdparty/singleapplication/singleapplication.h
vendored
@@ -1,153 +0,0 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) Itay Grudev 2015 - 2020
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//
|
||||
// W A R N I N G !!!
|
||||
// -----------------
|
||||
//
|
||||
// This is a modified version of SingleApplication,
|
||||
// The original version is at:
|
||||
//
|
||||
// https://github.com/itay-grudev/SingleApplication
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef SINGLEAPPLICATION_H
|
||||
#define SINGLEAPPLICATION_H
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QApplication>
|
||||
#include <QFlags>
|
||||
#include <QByteArray>
|
||||
|
||||
class SingleApplicationPrivate;
|
||||
|
||||
/**
|
||||
* @brief The SingleApplication class handles multiple instances of the same Application
|
||||
* @see QApplication
|
||||
*/
|
||||
class SingleApplication : public QApplication { // clazy:exclude=ctor-missing-parent-argument
|
||||
Q_OBJECT
|
||||
|
||||
typedef QApplication app_t;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Mode of operation of SingleApplication.
|
||||
* Whether the block should be user-wide or system-wide and whether the
|
||||
* primary instance should be notified when a secondary instance had been
|
||||
* started.
|
||||
* @note Operating system can restrict the shared memory blocks to the same
|
||||
* user, in which case the User/System modes will have no effect and the
|
||||
* block will be user wide.
|
||||
* @enum
|
||||
*/
|
||||
enum Mode {
|
||||
User = 1 << 0,
|
||||
System = 1 << 1,
|
||||
SecondaryNotification = 1 << 2,
|
||||
ExcludeAppVersion = 1 << 3,
|
||||
ExcludeAppPath = 1 << 4
|
||||
};
|
||||
Q_DECLARE_FLAGS(Options, Mode)
|
||||
|
||||
/**
|
||||
* @brief Intitializes a SingleApplication instance with argc command line
|
||||
* arguments in argv
|
||||
* @arg {int &} argc - Number of arguments in argv
|
||||
* @arg {const char *[]} argv - Supplied command line arguments
|
||||
* @arg {bool} allowSecondary - Whether to start the instance as secondary
|
||||
* if there is already a primary instance.
|
||||
* @arg {Mode} mode - Whether for the SingleApplication block to be applied
|
||||
* User wide or System wide.
|
||||
* @arg {int} timeout - Timeout to wait in milliseconds.
|
||||
* @note argc and argv may be changed as Qt removes arguments that it
|
||||
* recognizes
|
||||
* @note Mode::SecondaryNotification only works if set on both the primary
|
||||
* instance and the secondary instance.
|
||||
* @note The timeout is just a hint for the maximum time of blocking
|
||||
* operations. It does not guarantee that the SingleApplication
|
||||
* initialisation will be completed in given time, though is a good hint.
|
||||
* Usually 4*timeout would be the worst case (fail) scenario.
|
||||
* @see See the corresponding QAPPLICATION_CLASS constructor for reference
|
||||
*/
|
||||
explicit SingleApplication(int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000);
|
||||
~SingleApplication() override;
|
||||
|
||||
/**
|
||||
* @brief Returns if the instance is the primary instance
|
||||
* @returns {bool}
|
||||
*/
|
||||
bool isPrimary();
|
||||
|
||||
/**
|
||||
* @brief Returns if the instance is a secondary instance
|
||||
* @returns {bool}
|
||||
*/
|
||||
bool isSecondary();
|
||||
|
||||
/**
|
||||
* @brief Returns a unique identifier for the current instance
|
||||
* @returns {qint32}
|
||||
*/
|
||||
quint32 instanceId();
|
||||
|
||||
/**
|
||||
* @brief Returns the process ID (PID) of the primary instance
|
||||
* @returns {qint64}
|
||||
*/
|
||||
qint64 primaryPid();
|
||||
|
||||
/**
|
||||
* @brief Returns the username of the user running the primary instance
|
||||
* @returns {QString}
|
||||
*/
|
||||
QString primaryUser();
|
||||
|
||||
/**
|
||||
* @brief Returns the username of the current user
|
||||
* @returns {QString}
|
||||
*/
|
||||
QString currentUser();
|
||||
|
||||
/**
|
||||
* @brief Sends a message to the primary instance. Returns true on success.
|
||||
* @param {int} timeout - Timeout for connecting
|
||||
* @returns {bool}
|
||||
* @note sendMessage() will return false if invoked from the primary
|
||||
* instance.
|
||||
*/
|
||||
bool sendMessage(const QByteArray &message, const int timeout = 1000);
|
||||
|
||||
signals:
|
||||
void instanceStarted();
|
||||
void receivedMessage(quint32 instanceId, QByteArray message);
|
||||
|
||||
private:
|
||||
SingleApplicationPrivate *d_ptr;
|
||||
Q_DECLARE_PRIVATE(SingleApplication)
|
||||
void abortSafely();
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options)
|
||||
|
||||
#endif // SINGLEAPPLICATION_H
|
||||
471
3rdparty/singleapplication/singleapplication_p.cpp
vendored
@@ -1,471 +0,0 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) Itay Grudev 2015 - 2020
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//
|
||||
// W A R N I N G !!!
|
||||
// -----------------
|
||||
//
|
||||
// This is a modified version of SingleApplication,
|
||||
// The original version is at:
|
||||
//
|
||||
// https://github.com/itay-grudev/SingleApplication
|
||||
//
|
||||
//
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
# include <unistd.h>
|
||||
# include <sys/types.h>
|
||||
# include <pwd.h>
|
||||
#endif
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QIODevice>
|
||||
#include <QSharedMemory>
|
||||
#include <QByteArray>
|
||||
#include <QDataStream>
|
||||
#include <QCryptographicHash>
|
||||
#include <QLocalServer>
|
||||
#include <QLocalSocket>
|
||||
#include <QDir>
|
||||
#include <QElapsedTimer>
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
# include <QRandomGenerator>
|
||||
#else
|
||||
# include <QDateTime>
|
||||
#endif
|
||||
|
||||
#include "singleapplication.h"
|
||||
#include "singleapplication_p.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <windows.h>
|
||||
# include <lmcons.h>
|
||||
#endif
|
||||
|
||||
SingleApplicationPrivate::SingleApplicationPrivate(SingleApplication *ptr)
|
||||
: q_ptr(ptr),
|
||||
memory_(nullptr),
|
||||
socket_(nullptr),
|
||||
server_(nullptr),
|
||||
instanceNumber_(-1) {}
|
||||
|
||||
SingleApplicationPrivate::~SingleApplicationPrivate() {
|
||||
|
||||
if (socket_ != nullptr) {
|
||||
socket_->close();
|
||||
delete socket_;
|
||||
socket_ = nullptr;
|
||||
}
|
||||
|
||||
if (memory_ != nullptr) {
|
||||
memory_->lock();
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
||||
if (server_ != nullptr) {
|
||||
server_->close();
|
||||
delete server_;
|
||||
inst->primary = false;
|
||||
inst->primaryPid = -1;
|
||||
inst->primaryUser[0] = '\0';
|
||||
inst->checksum = blockChecksum();
|
||||
}
|
||||
memory_->unlock();
|
||||
|
||||
delete memory_;
|
||||
memory_ = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QString SingleApplicationPrivate::getUsername() {
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
QString username;
|
||||
#if defined(HAVE_GETEUID) && defined(HAVE_GETPWUID)
|
||||
struct passwd *pw = getpwuid(geteuid());
|
||||
if (pw) {
|
||||
username = QString::fromLocal8Bit(pw->pw_name);
|
||||
}
|
||||
#endif
|
||||
if (username.isEmpty()) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
username = qEnvironmentVariable("USER");
|
||||
#else
|
||||
username = QString::fromLocal8Bit(qgetenv("USER"));
|
||||
#endif
|
||||
}
|
||||
return username;
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
wchar_t username[UNLEN + 1];
|
||||
// Specifies size of the buffer on input
|
||||
DWORD usernameLength = UNLEN + 1;
|
||||
if (GetUserNameW(username, &usernameLength)) {
|
||||
return QString::fromWCharArray(username);
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
return qEnvironmentVariable("USERNAME");
|
||||
#else
|
||||
return QString::fromLocal8Bit(qgetenv("USERNAME"));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::genBlockServerName() {
|
||||
|
||||
QCryptographicHash appData(QCryptographicHash::Sha256);
|
||||
appData.addData("SingleApplication", 17);
|
||||
appData.addData(SingleApplication::app_t::applicationName().toUtf8());
|
||||
appData.addData(SingleApplication::app_t::organizationName().toUtf8());
|
||||
appData.addData(SingleApplication::app_t::organizationDomain().toUtf8());
|
||||
|
||||
if (!(options_ & SingleApplication::Mode::ExcludeAppVersion)) {
|
||||
appData.addData(SingleApplication::app_t::applicationVersion().toUtf8());
|
||||
}
|
||||
|
||||
if (!(options_ & SingleApplication::Mode::ExcludeAppPath)) {
|
||||
#ifdef Q_OS_WIN
|
||||
appData.addData(SingleApplication::app_t::applicationFilePath().toLower().toUtf8());
|
||||
#else
|
||||
appData.addData(SingleApplication::app_t::applicationFilePath().toUtf8());
|
||||
#endif
|
||||
}
|
||||
|
||||
// User level block requires a user specific data in the hash
|
||||
if (options_ & SingleApplication::Mode::User) {
|
||||
appData.addData(getUsername().toUtf8());
|
||||
}
|
||||
|
||||
// Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with server naming requirements.
|
||||
blockServerName_ = appData.result().toBase64().replace("/", "_");
|
||||
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::initializeMemoryBlock() const {
|
||||
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
||||
inst->primary = false;
|
||||
inst->secondary = 0;
|
||||
inst->primaryPid = -1;
|
||||
inst->primaryUser[0] = '\0';
|
||||
inst->checksum = blockChecksum();
|
||||
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::startPrimary() {
|
||||
|
||||
Q_Q(SingleApplication);
|
||||
|
||||
// Reset the number of connections
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
||||
|
||||
inst->primary = true;
|
||||
inst->primaryPid = q->applicationPid();
|
||||
qstrncpy(inst->primaryUser, getUsername().toUtf8().data(), sizeof(inst->primaryUser));
|
||||
inst->checksum = blockChecksum();
|
||||
instanceNumber_ = 0;
|
||||
// Successful creation means that no main process exists
|
||||
// So we start a QLocalServer to listen for connections
|
||||
QLocalServer::removeServer(blockServerName_);
|
||||
server_ = new QLocalServer();
|
||||
|
||||
// Restrict access to the socket according to the SingleApplication::Mode::User flag on User level or no restrictions
|
||||
if (options_ & SingleApplication::Mode::User) {
|
||||
server_->setSocketOptions(QLocalServer::UserAccessOption);
|
||||
}
|
||||
else {
|
||||
server_->setSocketOptions(QLocalServer::WorldAccessOption);
|
||||
}
|
||||
|
||||
server_->listen(blockServerName_);
|
||||
QObject::connect(server_, &QLocalServer::newConnection, this, &SingleApplicationPrivate::slotConnectionEstablished);
|
||||
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::startSecondary() {
|
||||
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
||||
|
||||
inst->secondary += 1;
|
||||
inst->checksum = blockChecksum();
|
||||
instanceNumber_ = inst->secondary;
|
||||
|
||||
}
|
||||
|
||||
bool SingleApplicationPrivate::connectToPrimary(const int timeout, const ConnectionType connectionType) {
|
||||
|
||||
QElapsedTimer time;
|
||||
time.start();
|
||||
|
||||
// Connect to the Local Server of the Primary Instance if not already connected.
|
||||
if (socket_ == nullptr) {
|
||||
socket_ = new QLocalSocket();
|
||||
}
|
||||
|
||||
if (socket_->state() == QLocalSocket::ConnectedState) return true;
|
||||
|
||||
if (socket_->state() != QLocalSocket::ConnectedState) {
|
||||
|
||||
forever {
|
||||
randomSleep();
|
||||
|
||||
if (socket_->state() != QLocalSocket::ConnectingState) {
|
||||
socket_->connectToServer(blockServerName_);
|
||||
}
|
||||
|
||||
if (socket_->state() == QLocalSocket::ConnectingState) {
|
||||
socket_->waitForConnected(static_cast<int>(timeout - time.elapsed()));
|
||||
}
|
||||
|
||||
// If connected break out of the loop
|
||||
if (socket_->state() == QLocalSocket::ConnectedState) break;
|
||||
|
||||
// If elapsed time since start is longer than the method timeout return
|
||||
if (time.elapsed() >= timeout) return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialisation message according to the SingleApplication protocol
|
||||
QByteArray initMsg;
|
||||
QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
|
||||
writeStream.setVersion(QDataStream::Qt_5_8);
|
||||
|
||||
writeStream << blockServerName_.toLatin1();
|
||||
writeStream << static_cast<quint8>(connectionType);
|
||||
writeStream << instanceNumber_;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
|
||||
#else
|
||||
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
|
||||
#endif
|
||||
|
||||
writeStream << checksum;
|
||||
|
||||
// The header indicates the message length that follows
|
||||
QByteArray header;
|
||||
QDataStream headerStream(&header, QIODevice::WriteOnly);
|
||||
headerStream.setVersion(QDataStream::Qt_5_8);
|
||||
headerStream << static_cast<quint64>(initMsg.length());
|
||||
|
||||
socket_->write(header);
|
||||
socket_->write(initMsg);
|
||||
bool result = socket_->waitForBytesWritten(static_cast<int>(timeout - time.elapsed()));
|
||||
socket_->flush();
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
quint16 SingleApplicationPrivate::blockChecksum() const {
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
quint16 checksum = qChecksum(QByteArray(static_cast<const char*>(memory_->constData()), offsetof(InstancesInfo, checksum)));
|
||||
#else
|
||||
quint16 checksum = qChecksum(static_cast<const char*>(memory_->constData()), offsetof(InstancesInfo, checksum));
|
||||
#endif
|
||||
|
||||
return checksum;
|
||||
|
||||
}
|
||||
|
||||
qint64 SingleApplicationPrivate::primaryPid() const {
|
||||
|
||||
memory_->lock();
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
||||
qint64 pid = inst->primaryPid;
|
||||
memory_->unlock();
|
||||
|
||||
return pid;
|
||||
|
||||
}
|
||||
|
||||
QString SingleApplicationPrivate::primaryUser() const {
|
||||
|
||||
memory_->lock();
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
||||
QByteArray username = inst->primaryUser;
|
||||
memory_->unlock();
|
||||
|
||||
return QString::fromUtf8(username);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Executed when a connection has been made to the LocalServer
|
||||
*/
|
||||
void SingleApplicationPrivate::slotConnectionEstablished() {
|
||||
|
||||
QLocalSocket *nextConnSocket = server_->nextPendingConnection();
|
||||
connectionMap_.insert(nextConnSocket, ConnectionInfo());
|
||||
|
||||
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
|
||||
const ConnectionInfo info = connectionMap_[nextConnSocket];
|
||||
slotClientConnectionClosed(nextConnSocket, info.instanceId);
|
||||
});
|
||||
|
||||
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, this, [nextConnSocket, this]() {
|
||||
connectionMap_.remove(nextConnSocket);
|
||||
nextConnSocket->deleteLater();
|
||||
});
|
||||
|
||||
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
|
||||
const ConnectionInfo info = connectionMap_[nextConnSocket];
|
||||
switch (info.stage) {
|
||||
case StageHeader:
|
||||
readInitMessageHeader(nextConnSocket);
|
||||
break;
|
||||
case StageBody:
|
||||
readInitMessageBody(nextConnSocket);
|
||||
break;
|
||||
case StageConnected:
|
||||
slotDataAvailable(nextConnSocket, info.instanceId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::readInitMessageHeader(QLocalSocket *sock) {
|
||||
|
||||
if (!connectionMap_.contains(sock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sock->bytesAvailable() < static_cast<qint64>(sizeof(quint64))) {
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream headerStream(sock);
|
||||
headerStream.setVersion(QDataStream::Qt_5_8);
|
||||
|
||||
// Read the header to know the message length
|
||||
quint64 msgLen = 0;
|
||||
headerStream >> msgLen;
|
||||
ConnectionInfo &info = connectionMap_[sock];
|
||||
info.stage = StageBody;
|
||||
info.msgLen = msgLen;
|
||||
|
||||
if (sock->bytesAvailable() >= static_cast<qint64>(msgLen)) {
|
||||
readInitMessageBody(sock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
|
||||
|
||||
Q_Q(SingleApplication);
|
||||
|
||||
if (!connectionMap_.contains(sock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConnectionInfo &info = connectionMap_[sock];
|
||||
if (sock->bytesAvailable() < static_cast<qint64>(info.msgLen)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the message body
|
||||
QByteArray msgBytes = sock->read(info.msgLen);
|
||||
QDataStream readStream(msgBytes);
|
||||
readStream.setVersion(QDataStream::Qt_5_8);
|
||||
|
||||
// server name
|
||||
QByteArray latin1Name;
|
||||
readStream >> latin1Name;
|
||||
|
||||
// connection type
|
||||
ConnectionType connectionType = InvalidConnection;
|
||||
quint8 connTypeVal = InvalidConnection;
|
||||
readStream >> connTypeVal;
|
||||
connectionType = static_cast<ConnectionType>(connTypeVal);
|
||||
|
||||
// instance id
|
||||
quint32 instanceId = 0;
|
||||
readStream >> instanceId;
|
||||
|
||||
// checksum
|
||||
quint16 msgChecksum = 0;
|
||||
readStream >> msgChecksum;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
const quint16 actualChecksum = qChecksum(QByteArray(msgBytes, static_cast<quint32>(msgBytes.length() - sizeof(quint16))));
|
||||
#else
|
||||
const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length() - sizeof(quint16)));
|
||||
#endif
|
||||
|
||||
bool isValid = readStream.status() == QDataStream::Ok && QLatin1String(latin1Name) == blockServerName_ && msgChecksum == actualChecksum;
|
||||
|
||||
if (!isValid) {
|
||||
sock->close();
|
||||
return;
|
||||
}
|
||||
|
||||
info.instanceId = instanceId;
|
||||
info.stage = StageConnected;
|
||||
|
||||
if (connectionType == NewInstance || (connectionType == SecondaryInstance && options_ & SingleApplication::Mode::SecondaryNotification)) {
|
||||
Q_EMIT q->instanceStarted();
|
||||
}
|
||||
|
||||
if (sock->bytesAvailable() > 0) {
|
||||
slotDataAvailable(sock, instanceId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, const quint32 instanceId) {
|
||||
|
||||
Q_Q(SingleApplication);
|
||||
Q_EMIT q->receivedMessage(instanceId, dataSocket->readAll());
|
||||
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::slotClientConnectionClosed(QLocalSocket *closedSocket, const quint32 instanceId) {
|
||||
|
||||
if (closedSocket->bytesAvailable() > 0) {
|
||||
slotDataAvailable(closedSocket, instanceId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::randomSleep() {
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
QThread::msleep(QRandomGenerator::global()->bounded(8U, 18U));
|
||||
#else
|
||||
qsrand(QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max());
|
||||
QThread::msleep(8 + static_cast<unsigned long>(static_cast<float>(qrand()) / RAND_MAX * 10));
|
||||
#endif
|
||||
|
||||
}
|
||||
111
3rdparty/singleapplication/singleapplication_p.h
vendored
@@ -1,111 +0,0 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) Itay Grudev 2015 - 2020
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//
|
||||
// W A R N I N G !!!
|
||||
// -----------------
|
||||
//
|
||||
// This is a modified version of SingleApplication,
|
||||
// The original version is at:
|
||||
//
|
||||
// https://github.com/itay-grudev/SingleApplication
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef SINGLEAPPLICATION_P_H
|
||||
#define SINGLEAPPLICATION_P_H
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
|
||||
#include "singleapplication.h"
|
||||
|
||||
class QLocalServer;
|
||||
class QLocalSocket;
|
||||
class QSharedMemory;
|
||||
|
||||
struct InstancesInfo {
|
||||
bool primary;
|
||||
quint32 secondary;
|
||||
qint64 primaryPid;
|
||||
char primaryUser[128];
|
||||
quint16 checksum;
|
||||
};
|
||||
|
||||
struct ConnectionInfo {
|
||||
explicit ConnectionInfo() : msgLen(0), instanceId(0), stage(0) {}
|
||||
quint64 msgLen;
|
||||
quint32 instanceId;
|
||||
quint8 stage;
|
||||
};
|
||||
|
||||
class SingleApplicationPrivate : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ConnectionType : quint8 {
|
||||
InvalidConnection = 0,
|
||||
NewInstance = 1,
|
||||
SecondaryInstance = 2,
|
||||
Reconnect = 3
|
||||
};
|
||||
enum ConnectionStage : quint8 {
|
||||
StageHeader = 0,
|
||||
StageBody = 1,
|
||||
StageConnected = 2,
|
||||
};
|
||||
Q_DECLARE_PUBLIC(SingleApplication)
|
||||
|
||||
explicit SingleApplicationPrivate(SingleApplication *ptr);
|
||||
~SingleApplicationPrivate() override;
|
||||
|
||||
static QString getUsername();
|
||||
void genBlockServerName();
|
||||
void initializeMemoryBlock() const;
|
||||
void startPrimary();
|
||||
void startSecondary();
|
||||
bool connectToPrimary(const int timeout, const ConnectionType connectionType);
|
||||
quint16 blockChecksum() const;
|
||||
qint64 primaryPid() const;
|
||||
QString primaryUser() const;
|
||||
void readInitMessageHeader(QLocalSocket *socket);
|
||||
void readInitMessageBody(QLocalSocket *socket);
|
||||
static void randomSleep();
|
||||
|
||||
SingleApplication *q_ptr;
|
||||
QSharedMemory *memory_;
|
||||
QLocalSocket *socket_;
|
||||
QLocalServer *server_;
|
||||
quint32 instanceNumber_;
|
||||
QString blockServerName_;
|
||||
SingleApplication::Options options_;
|
||||
QHash<QLocalSocket*, ConnectionInfo> connectionMap_;
|
||||
|
||||
public slots:
|
||||
void slotConnectionEstablished();
|
||||
void slotDataAvailable(QLocalSocket*, const quint32);
|
||||
void slotClientConnectionClosed(QLocalSocket*, const quint32);
|
||||
};
|
||||
|
||||
#endif // SINGLEAPPLICATION_P_H
|
||||
270
3rdparty/singleapplication/singlecoreapplication.cpp
vendored
@@ -1,270 +0,0 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) Itay Grudev 2015 - 2020
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//
|
||||
// W A R N I N G !!!
|
||||
// -----------------
|
||||
//
|
||||
// This is a modified version of SingleApplication,
|
||||
// The original version is at:
|
||||
//
|
||||
// https://github.com/itay-grudev/SingleApplication
|
||||
//
|
||||
//
|
||||
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QCoreApplication>
|
||||
#include <QThread>
|
||||
#include <QSharedMemory>
|
||||
#include <QLocalSocket>
|
||||
#include <QByteArray>
|
||||
#include <QElapsedTimer>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "singlecoreapplication.h"
|
||||
#include "singlecoreapplication_p.h"
|
||||
|
||||
/**
|
||||
* @brief Constructor. Checks and fires up LocalServer or closes the program if another instance already exists
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param allowSecondary Whether to enable secondary instance support
|
||||
* @param options Optional flags to toggle specific behaviour
|
||||
* @param timeout Maximum time blocking functions are allowed during app load
|
||||
*/
|
||||
SingleCoreApplication::SingleCoreApplication(int &argc, char *argv[], bool allowSecondary, Options options, int timeout)
|
||||
: app_t(argc, argv),
|
||||
d_ptr(new SingleCoreApplicationPrivate(this)) {
|
||||
|
||||
Q_D(SingleCoreApplication);
|
||||
|
||||
// Store the current mode of the program
|
||||
d->options_ = options;
|
||||
|
||||
// Generating an application ID used for identifying the shared memory block and QLocalServer
|
||||
d->genBlockServerName();
|
||||
|
||||
// To mitigate QSharedMemory issues with large amount of processes attempting to attach at the same time
|
||||
d->randomSleep();
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
// By explicitly attaching it and then deleting it we make sure that the memory is deleted even after the process has crashed on Unix.
|
||||
d->memory_ = new QSharedMemory(d->blockServerName_);
|
||||
d->memory_->attach();
|
||||
delete d->memory_;
|
||||
#endif
|
||||
|
||||
// Guarantee thread safe behaviour with a shared memory block.
|
||||
d->memory_ = new QSharedMemory(d->blockServerName_);
|
||||
|
||||
// Create a shared memory block
|
||||
if (d->memory_->create(sizeof(InstancesInfo))) {
|
||||
// Initialize the shared memory block
|
||||
if (!d->memory_->lock()) {
|
||||
qCritical() << "SingleCoreApplication: Unable to lock memory block after create.";
|
||||
abortSafely();
|
||||
}
|
||||
d->initializeMemoryBlock();
|
||||
}
|
||||
else {
|
||||
if (d->memory_->error() == QSharedMemory::AlreadyExists) {
|
||||
// Attempt to attach to the memory segment
|
||||
if (!d->memory_->attach()) {
|
||||
qCritical() << "SingleCoreApplication: Unable to attach to shared memory block.";
|
||||
abortSafely();
|
||||
}
|
||||
if (!d->memory_->lock()) {
|
||||
qCritical() << "SingleCoreApplication: Unable to lock memory block after attach.";
|
||||
abortSafely();
|
||||
}
|
||||
}
|
||||
else {
|
||||
qCritical() << "SingleCoreApplication: Unable to create block.";
|
||||
abortSafely();
|
||||
}
|
||||
}
|
||||
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(d->memory_->data());
|
||||
QElapsedTimer time;
|
||||
time.start();
|
||||
|
||||
// Make sure the shared memory block is initialised and in consistent state
|
||||
forever {
|
||||
// If the shared memory block's checksum is valid continue
|
||||
if (d->blockChecksum() == inst->checksum) break;
|
||||
|
||||
// If more than 5s have elapsed, assume the primary instance crashed and assume it's position
|
||||
if (time.elapsed() > 5000) {
|
||||
qWarning() << "SingleCoreApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure.";
|
||||
d->initializeMemoryBlock();
|
||||
}
|
||||
|
||||
// Otherwise wait for a random period and try again.
|
||||
// The random sleep here limits the probability of a collision between two racing apps and allows the app to initialise faster
|
||||
if (!d->memory_->unlock()) {
|
||||
qDebug() << "SingleCoreApplication: Unable to unlock memory for random wait.";
|
||||
qDebug() << d->memory_->errorString();
|
||||
}
|
||||
d->randomSleep();
|
||||
if (!d->memory_->lock()) {
|
||||
qCritical() << "SingleCoreApplication: Unable to lock memory after random wait.";
|
||||
abortSafely();
|
||||
}
|
||||
}
|
||||
|
||||
if (!inst->primary) {
|
||||
d->startPrimary();
|
||||
if (!d->memory_->unlock()) {
|
||||
qDebug() << "SingleCoreApplication: Unable to unlock memory after primary start.";
|
||||
qDebug() << d->memory_->errorString();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if another instance can be started
|
||||
if (allowSecondary) {
|
||||
d->startSecondary();
|
||||
if (d->options_ & Mode::SecondaryNotification) {
|
||||
d->connectToPrimary(timeout, SingleCoreApplicationPrivate::SecondaryInstance);
|
||||
}
|
||||
if (!d->memory_->unlock()) {
|
||||
qDebug() << "SingleCoreApplication: Unable to unlock memory after secondary start.";
|
||||
qDebug() << d->memory_->errorString();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!d->memory_->unlock()) {
|
||||
qDebug() << "SingleCoreApplication: Unable to unlock memory at end of execution.";
|
||||
qDebug() << d->memory_->errorString();
|
||||
}
|
||||
|
||||
d->connectToPrimary(timeout, SingleCoreApplicationPrivate::NewInstance);
|
||||
|
||||
delete d;
|
||||
|
||||
::exit(EXIT_SUCCESS);
|
||||
|
||||
}
|
||||
|
||||
SingleCoreApplication::~SingleCoreApplication() {
|
||||
Q_D(SingleCoreApplication);
|
||||
delete d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current application instance is primary.
|
||||
* @return Returns true if the instance is primary, false otherwise.
|
||||
*/
|
||||
bool SingleCoreApplication::isPrimary() {
|
||||
Q_D(SingleCoreApplication);
|
||||
return d->server_ != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current application instance is secondary.
|
||||
* @return Returns true if the instance is secondary, false otherwise.
|
||||
*/
|
||||
bool SingleCoreApplication::isSecondary() {
|
||||
Q_D(SingleCoreApplication);
|
||||
return d->server_ == nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to identify an instance by returning unique consecutive instance ids.
|
||||
* It is reset when the first (primary) instance of your app starts and only incremented afterwards.
|
||||
* @return Returns a unique instance id.
|
||||
*/
|
||||
quint32 SingleCoreApplication::instanceId() {
|
||||
Q_D(SingleCoreApplication);
|
||||
return d->instanceNumber_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the OS PID (Process Identifier) of the process running the primary instance.
|
||||
* Especially useful when SingleCoreApplication is coupled with OS. specific APIs.
|
||||
* @return Returns the primary instance PID.
|
||||
*/
|
||||
qint64 SingleCoreApplication::primaryPid() {
|
||||
Q_D(SingleCoreApplication);
|
||||
return d->primaryPid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the username the primary instance is running as.
|
||||
* @return Returns the username the primary instance is running as.
|
||||
*/
|
||||
QString SingleCoreApplication::primaryUser() {
|
||||
Q_D(SingleCoreApplication);
|
||||
return d->primaryUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the username the current instance is running as.
|
||||
* @return Returns the username the current instance is running as.
|
||||
*/
|
||||
QString SingleCoreApplication::currentUser() {
|
||||
Q_D(SingleCoreApplication);
|
||||
return d->getUsername();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends message to the Primary Instance.
|
||||
* @param message The message to send.
|
||||
* @param timeout the maximum timeout in milliseconds for blocking functions.
|
||||
* @return true if the message was sent successfully, false otherwise.
|
||||
*/
|
||||
bool SingleCoreApplication::sendMessage(const QByteArray &message, const int timeout) {
|
||||
|
||||
Q_D(SingleCoreApplication);
|
||||
|
||||
// Nobody to connect to
|
||||
if (isPrimary()) return false;
|
||||
|
||||
// Make sure the socket is connected
|
||||
if (!d->connectToPrimary(timeout, SingleCoreApplicationPrivate::Reconnect)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
d->socket_->write(message);
|
||||
const bool dataWritten = d->socket_->waitForBytesWritten(timeout);
|
||||
d->socket_->flush();
|
||||
return dataWritten;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the shared memory block and exits with a failure.
|
||||
* This function halts program execution.
|
||||
*/
|
||||
void SingleCoreApplication::abortSafely() {
|
||||
|
||||
Q_D(SingleCoreApplication);
|
||||
|
||||
qCritical() << "SingleCoreApplication: " << d->memory_->error() << d->memory_->errorString();
|
||||
delete d;
|
||||
::exit(EXIT_FAILURE);
|
||||
|
||||
}
|
||||
152
3rdparty/singleapplication/singlecoreapplication.h
vendored
@@ -1,152 +0,0 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) Itay Grudev 2015 - 2020
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//
|
||||
// W A R N I N G !!!
|
||||
// -----------------
|
||||
//
|
||||
// This is a modified version of SingleApplication,
|
||||
// The original version is at:
|
||||
//
|
||||
// https://github.com/itay-grudev/SingleApplication
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef SINGLECOREAPPLICATION_H
|
||||
#define SINGLECOREAPPLICATION_H
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QCoreApplication>
|
||||
#include <QFlags>
|
||||
#include <QByteArray>
|
||||
|
||||
class SingleCoreApplicationPrivate;
|
||||
|
||||
/**
|
||||
* @brief The SingleCoreApplication class handles multiple instances of the same Application
|
||||
* @see QCoreApplication
|
||||
*/
|
||||
class SingleCoreApplication : public QCoreApplication {
|
||||
Q_OBJECT
|
||||
|
||||
typedef QCoreApplication app_t;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Mode of operation of SingleCoreApplication.
|
||||
* Whether the block should be user-wide or system-wide and whether the
|
||||
* primary instance should be notified when a secondary instance had been
|
||||
* started.
|
||||
* @note Operating system can restrict the shared memory blocks to the same
|
||||
* user, in which case the User/System modes will have no effect and the
|
||||
* block will be user wide.
|
||||
* @enum
|
||||
*/
|
||||
enum Mode {
|
||||
User = 1 << 0,
|
||||
System = 1 << 1,
|
||||
SecondaryNotification = 1 << 2,
|
||||
ExcludeAppVersion = 1 << 3,
|
||||
ExcludeAppPath = 1 << 4
|
||||
};
|
||||
Q_DECLARE_FLAGS(Options, Mode)
|
||||
|
||||
/**
|
||||
* @brief Intitializes a SingleCoreApplication instance with argc command line
|
||||
* arguments in argv
|
||||
* @arg {int &} argc - Number of arguments in argv
|
||||
* @arg {const char *[]} argv - Supplied command line arguments
|
||||
* @arg {bool} allowSecondary - Whether to start the instance as secondary
|
||||
* if there is already a primary instance.
|
||||
* @arg {Mode} mode - Whether for the SingleCoreApplication block to be applied
|
||||
* User wide or System wide.
|
||||
* @arg {int} timeout - Timeout to wait in milliseconds.
|
||||
* @note argc and argv may be changed as Qt removes arguments that it
|
||||
* recognizes
|
||||
* @note Mode::SecondaryNotification only works if set on both the primary
|
||||
* instance and the secondary instance.
|
||||
* @note The timeout is just a hint for the maximum time of blocking
|
||||
* operations. It does not guarantee that the SingleCoreApplication
|
||||
* initialisation will be completed in given time, though is a good hint.
|
||||
* Usually 4*timeout would be the worst case (fail) scenario.
|
||||
*/
|
||||
explicit SingleCoreApplication(int &argc, char *argv[], const bool allowSecondary = false, const Options options = Mode::User, const int timeout = 1000);
|
||||
~SingleCoreApplication() override;
|
||||
|
||||
/**
|
||||
* @brief Returns if the instance is the primary instance
|
||||
* @returns {bool}
|
||||
*/
|
||||
bool isPrimary();
|
||||
|
||||
/**
|
||||
* @brief Returns if the instance is a secondary instance
|
||||
* @returns {bool}
|
||||
*/
|
||||
bool isSecondary();
|
||||
|
||||
/**
|
||||
* @brief Returns a unique identifier for the current instance
|
||||
* @returns {qint32}
|
||||
*/
|
||||
quint32 instanceId();
|
||||
|
||||
/**
|
||||
* @brief Returns the process ID (PID) of the primary instance
|
||||
* @returns {qint64}
|
||||
*/
|
||||
qint64 primaryPid();
|
||||
|
||||
/**
|
||||
* @brief Returns the username of the user running the primary instance
|
||||
* @returns {QString}
|
||||
*/
|
||||
QString primaryUser();
|
||||
|
||||
/**
|
||||
* @brief Returns the username of the current user
|
||||
* @returns {QString}
|
||||
*/
|
||||
QString currentUser();
|
||||
|
||||
/**
|
||||
* @brief Sends a message to the primary instance. Returns true on success.
|
||||
* @param {int} timeout - Timeout for connecting
|
||||
* @returns {bool}
|
||||
* @note sendMessage() will return false if invoked from the primary
|
||||
* instance.
|
||||
*/
|
||||
bool sendMessage(const QByteArray &message, const int timeout = 1000);
|
||||
|
||||
signals:
|
||||
void instanceStarted();
|
||||
void receivedMessage(quint32 instanceId, QByteArray message);
|
||||
|
||||
private:
|
||||
SingleCoreApplicationPrivate *d_ptr;
|
||||
Q_DECLARE_PRIVATE(SingleCoreApplication)
|
||||
void abortSafely();
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(SingleCoreApplication::Options)
|
||||
|
||||
#endif // SINGLECOREAPPLICATION_H
|
||||
@@ -1,471 +0,0 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) Itay Grudev 2015 - 2020
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//
|
||||
// W A R N I N G !!!
|
||||
// -----------------
|
||||
//
|
||||
// This is a modified version of SingleApplication,
|
||||
// The original version is at:
|
||||
//
|
||||
// https://github.com/itay-grudev/SingleApplication
|
||||
//
|
||||
//
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
# include <unistd.h>
|
||||
# include <sys/types.h>
|
||||
# include <pwd.h>
|
||||
#endif
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QIODevice>
|
||||
#include <QSharedMemory>
|
||||
#include <QByteArray>
|
||||
#include <QDataStream>
|
||||
#include <QCryptographicHash>
|
||||
#include <QLocalServer>
|
||||
#include <QLocalSocket>
|
||||
#include <QDir>
|
||||
#include <QElapsedTimer>
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
# include <QRandomGenerator>
|
||||
#else
|
||||
# include <QDateTime>
|
||||
#endif
|
||||
|
||||
#include "singlecoreapplication.h"
|
||||
#include "singlecoreapplication_p.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <windows.h>
|
||||
# include <lmcons.h>
|
||||
#endif
|
||||
|
||||
SingleCoreApplicationPrivate::SingleCoreApplicationPrivate(SingleCoreApplication *ptr)
|
||||
: q_ptr(ptr),
|
||||
memory_(nullptr),
|
||||
socket_(nullptr),
|
||||
server_(nullptr),
|
||||
instanceNumber_(-1) {}
|
||||
|
||||
SingleCoreApplicationPrivate::~SingleCoreApplicationPrivate() {
|
||||
|
||||
if (socket_ != nullptr) {
|
||||
socket_->close();
|
||||
delete socket_;
|
||||
socket_ = nullptr;
|
||||
}
|
||||
|
||||
if (memory_ != nullptr) {
|
||||
memory_->lock();
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
||||
if (server_ != nullptr) {
|
||||
server_->close();
|
||||
delete server_;
|
||||
inst->primary = false;
|
||||
inst->primaryPid = -1;
|
||||
inst->primaryUser[0] = '\0';
|
||||
inst->checksum = blockChecksum();
|
||||
}
|
||||
memory_->unlock();
|
||||
|
||||
delete memory_;
|
||||
memory_ = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QString SingleCoreApplicationPrivate::getUsername() {
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
QString username;
|
||||
#if defined(HAVE_GETEUID) && defined(HAVE_GETPWUID)
|
||||
struct passwd *pw = getpwuid(geteuid());
|
||||
if (pw) {
|
||||
username = QString::fromLocal8Bit(pw->pw_name);
|
||||
}
|
||||
#endif
|
||||
if (username.isEmpty()) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
username = qEnvironmentVariable("USER");
|
||||
#else
|
||||
username = QString::fromLocal8Bit(qgetenv("USER"));
|
||||
#endif
|
||||
}
|
||||
return username;
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
wchar_t username[UNLEN + 1];
|
||||
// Specifies size of the buffer on input
|
||||
DWORD usernameLength = UNLEN + 1;
|
||||
if (GetUserNameW(username, &usernameLength)) {
|
||||
return QString::fromWCharArray(username);
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
return qEnvironmentVariable("USERNAME");
|
||||
#else
|
||||
return QString::fromLocal8Bit(qgetenv("USERNAME"));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void SingleCoreApplicationPrivate::genBlockServerName() {
|
||||
|
||||
QCryptographicHash appData(QCryptographicHash::Sha256);
|
||||
appData.addData("SingleApplication", 17);
|
||||
appData.addData(SingleCoreApplication::app_t::applicationName().toUtf8());
|
||||
appData.addData(SingleCoreApplication::app_t::organizationName().toUtf8());
|
||||
appData.addData(SingleCoreApplication::app_t::organizationDomain().toUtf8());
|
||||
|
||||
if (!(options_ & SingleCoreApplication::Mode::ExcludeAppVersion)) {
|
||||
appData.addData(SingleCoreApplication::app_t::applicationVersion().toUtf8());
|
||||
}
|
||||
|
||||
if (!(options_ & SingleCoreApplication::Mode::ExcludeAppPath)) {
|
||||
#ifdef Q_OS_WIN
|
||||
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toLower().toUtf8());
|
||||
#else
|
||||
appData.addData(SingleCoreApplication::app_t::applicationFilePath().toUtf8());
|
||||
#endif
|
||||
}
|
||||
|
||||
// User level block requires a user specific data in the hash
|
||||
if (options_ & SingleCoreApplication::Mode::User) {
|
||||
appData.addData(getUsername().toUtf8());
|
||||
}
|
||||
|
||||
// Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with server naming requirements.
|
||||
blockServerName_ = appData.result().toBase64().replace("/", "_");
|
||||
|
||||
}
|
||||
|
||||
void SingleCoreApplicationPrivate::initializeMemoryBlock() const {
|
||||
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
||||
inst->primary = false;
|
||||
inst->secondary = 0;
|
||||
inst->primaryPid = -1;
|
||||
inst->primaryUser[0] = '\0';
|
||||
inst->checksum = blockChecksum();
|
||||
|
||||
}
|
||||
|
||||
void SingleCoreApplicationPrivate::startPrimary() {
|
||||
|
||||
Q_Q(SingleCoreApplication);
|
||||
|
||||
// Reset the number of connections
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
||||
|
||||
inst->primary = true;
|
||||
inst->primaryPid = q->applicationPid();
|
||||
qstrncpy(inst->primaryUser, getUsername().toUtf8().data(), sizeof(inst->primaryUser));
|
||||
inst->checksum = blockChecksum();
|
||||
instanceNumber_ = 0;
|
||||
// Successful creation means that no main process exists
|
||||
// So we start a QLocalServer to listen for connections
|
||||
QLocalServer::removeServer(blockServerName_);
|
||||
server_ = new QLocalServer();
|
||||
|
||||
// Restrict access to the socket according to the SingleCoreApplication::Mode::User flag on User level or no restrictions
|
||||
if (options_ & SingleCoreApplication::Mode::User) {
|
||||
server_->setSocketOptions(QLocalServer::UserAccessOption);
|
||||
}
|
||||
else {
|
||||
server_->setSocketOptions(QLocalServer::WorldAccessOption);
|
||||
}
|
||||
|
||||
server_->listen(blockServerName_);
|
||||
QObject::connect(server_, &QLocalServer::newConnection, this, &SingleCoreApplicationPrivate::slotConnectionEstablished);
|
||||
|
||||
}
|
||||
|
||||
void SingleCoreApplicationPrivate::startSecondary() {
|
||||
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
||||
|
||||
inst->secondary += 1;
|
||||
inst->checksum = blockChecksum();
|
||||
instanceNumber_ = inst->secondary;
|
||||
|
||||
}
|
||||
|
||||
bool SingleCoreApplicationPrivate::connectToPrimary(const int timeout, const ConnectionType connectionType) {
|
||||
|
||||
QElapsedTimer time;
|
||||
time.start();
|
||||
|
||||
// Connect to the Local Server of the Primary Instance if not already connected.
|
||||
if (socket_ == nullptr) {
|
||||
socket_ = new QLocalSocket();
|
||||
}
|
||||
|
||||
if (socket_->state() == QLocalSocket::ConnectedState) return true;
|
||||
|
||||
if (socket_->state() != QLocalSocket::ConnectedState) {
|
||||
|
||||
forever {
|
||||
randomSleep();
|
||||
|
||||
if (socket_->state() != QLocalSocket::ConnectingState) {
|
||||
socket_->connectToServer(blockServerName_);
|
||||
}
|
||||
|
||||
if (socket_->state() == QLocalSocket::ConnectingState) {
|
||||
socket_->waitForConnected(static_cast<int>(timeout - time.elapsed()));
|
||||
}
|
||||
|
||||
// If connected break out of the loop
|
||||
if (socket_->state() == QLocalSocket::ConnectedState) break;
|
||||
|
||||
// If elapsed time since start is longer than the method timeout return
|
||||
if (time.elapsed() >= timeout) return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialisation message according to the SingleCoreApplication protocol
|
||||
QByteArray initMsg;
|
||||
QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
|
||||
writeStream.setVersion(QDataStream::Qt_5_8);
|
||||
|
||||
writeStream << blockServerName_.toLatin1();
|
||||
writeStream << static_cast<quint8>(connectionType);
|
||||
writeStream << instanceNumber_;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
|
||||
#else
|
||||
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
|
||||
#endif
|
||||
|
||||
writeStream << checksum;
|
||||
|
||||
// The header indicates the message length that follows
|
||||
QByteArray header;
|
||||
QDataStream headerStream(&header, QIODevice::WriteOnly);
|
||||
headerStream.setVersion(QDataStream::Qt_5_8);
|
||||
headerStream << static_cast<quint64>(initMsg.length());
|
||||
|
||||
socket_->write(header);
|
||||
socket_->write(initMsg);
|
||||
bool result = socket_->waitForBytesWritten(timeout - static_cast<int>(time.elapsed()));
|
||||
socket_->flush();
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
quint16 SingleCoreApplicationPrivate::blockChecksum() const {
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
quint16 checksum = qChecksum(QByteArray(static_cast<const char*>(memory_->constData()), offsetof(InstancesInfo, checksum)));
|
||||
#else
|
||||
quint16 checksum = qChecksum(static_cast<const char*>(memory_->constData()), offsetof(InstancesInfo, checksum));
|
||||
#endif
|
||||
|
||||
return checksum;
|
||||
|
||||
}
|
||||
|
||||
qint64 SingleCoreApplicationPrivate::primaryPid() const {
|
||||
|
||||
memory_->lock();
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
||||
qint64 pid = inst->primaryPid;
|
||||
memory_->unlock();
|
||||
|
||||
return pid;
|
||||
|
||||
}
|
||||
|
||||
QString SingleCoreApplicationPrivate::primaryUser() const {
|
||||
|
||||
memory_->lock();
|
||||
InstancesInfo *inst = static_cast<InstancesInfo*>(memory_->data());
|
||||
QByteArray username = inst->primaryUser;
|
||||
memory_->unlock();
|
||||
|
||||
return QString::fromUtf8(username);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Executed when a connection has been made to the LocalServer
|
||||
*/
|
||||
void SingleCoreApplicationPrivate::slotConnectionEstablished() {
|
||||
|
||||
QLocalSocket *nextConnSocket = server_->nextPendingConnection();
|
||||
connectionMap_.insert(nextConnSocket, ConnectionInfo());
|
||||
|
||||
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this, [nextConnSocket, this]() {
|
||||
const ConnectionInfo info = connectionMap_[nextConnSocket];
|
||||
slotClientConnectionClosed(nextConnSocket, info.instanceId);
|
||||
});
|
||||
|
||||
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, this, [nextConnSocket, this]() {
|
||||
connectionMap_.remove(nextConnSocket);
|
||||
nextConnSocket->deleteLater();
|
||||
});
|
||||
|
||||
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this, [nextConnSocket, this]() {
|
||||
const ConnectionInfo info = connectionMap_[nextConnSocket];
|
||||
switch (info.stage) {
|
||||
case StageHeader:
|
||||
readInitMessageHeader(nextConnSocket);
|
||||
break;
|
||||
case StageBody:
|
||||
readInitMessageBody(nextConnSocket);
|
||||
break;
|
||||
case StageConnected:
|
||||
slotDataAvailable(nextConnSocket, info.instanceId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void SingleCoreApplicationPrivate::readInitMessageHeader(QLocalSocket *sock) {
|
||||
|
||||
if (!connectionMap_.contains(sock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sock->bytesAvailable() < static_cast<qint64>(sizeof(quint64))) {
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream headerStream(sock);
|
||||
headerStream.setVersion(QDataStream::Qt_5_8);
|
||||
|
||||
// Read the header to know the message length
|
||||
quint64 msgLen = 0;
|
||||
headerStream >> msgLen;
|
||||
ConnectionInfo &info = connectionMap_[sock];
|
||||
info.stage = StageBody;
|
||||
info.msgLen = msgLen;
|
||||
|
||||
if (sock->bytesAvailable() >= static_cast<qint64>(msgLen)) {
|
||||
readInitMessageBody(sock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SingleCoreApplicationPrivate::readInitMessageBody(QLocalSocket *sock) {
|
||||
|
||||
Q_Q(SingleCoreApplication);
|
||||
|
||||
if (!connectionMap_.contains(sock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConnectionInfo &info = connectionMap_[sock];
|
||||
if (sock->bytesAvailable() < static_cast<qint64>(info.msgLen)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the message body
|
||||
QByteArray msgBytes = sock->read(info.msgLen);
|
||||
QDataStream readStream(msgBytes);
|
||||
readStream.setVersion(QDataStream::Qt_5_8);
|
||||
|
||||
// server name
|
||||
QByteArray latin1Name;
|
||||
readStream >> latin1Name;
|
||||
|
||||
// connection type
|
||||
ConnectionType connectionType = InvalidConnection;
|
||||
quint8 connTypeVal = InvalidConnection;
|
||||
readStream >> connTypeVal;
|
||||
connectionType = static_cast<ConnectionType>(connTypeVal);
|
||||
|
||||
// instance id
|
||||
quint32 instanceId = 0;
|
||||
readStream >> instanceId;
|
||||
|
||||
// checksum
|
||||
quint16 msgChecksum = 0;
|
||||
readStream >> msgChecksum;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
const quint16 actualChecksum = qChecksum(QByteArray(msgBytes, static_cast<quint32>(msgBytes.length() - sizeof(quint16))));
|
||||
#else
|
||||
const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length() - sizeof(quint16)));
|
||||
#endif
|
||||
|
||||
bool isValid = readStream.status() == QDataStream::Ok && QLatin1String(latin1Name) == blockServerName_ && msgChecksum == actualChecksum;
|
||||
|
||||
if (!isValid) {
|
||||
sock->close();
|
||||
return;
|
||||
}
|
||||
|
||||
info.instanceId = instanceId;
|
||||
info.stage = StageConnected;
|
||||
|
||||
if (connectionType == NewInstance || (connectionType == SecondaryInstance && options_ & SingleCoreApplication::Mode::SecondaryNotification)) {
|
||||
Q_EMIT q->instanceStarted();
|
||||
}
|
||||
|
||||
if (sock->bytesAvailable() > 0) {
|
||||
slotDataAvailable(sock, instanceId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SingleCoreApplicationPrivate::slotDataAvailable(QLocalSocket *dataSocket, const quint32 instanceId) {
|
||||
|
||||
Q_Q(SingleCoreApplication);
|
||||
Q_EMIT q->receivedMessage(instanceId, dataSocket->readAll());
|
||||
|
||||
}
|
||||
|
||||
void SingleCoreApplicationPrivate::slotClientConnectionClosed(QLocalSocket *closedSocket, const quint32 instanceId) {
|
||||
|
||||
if (closedSocket->bytesAvailable() > 0) {
|
||||
slotDataAvailable(closedSocket, instanceId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SingleCoreApplicationPrivate::randomSleep() {
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
QThread::msleep(QRandomGenerator::global()->bounded(8U, 18U));
|
||||
#else
|
||||
qsrand(QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max());
|
||||
QThread::msleep(8 + static_cast<unsigned long>(static_cast<float>(qrand()) / RAND_MAX * 10));
|
||||
#endif
|
||||
|
||||
}
|
||||
111
3rdparty/singleapplication/singlecoreapplication_p.h
vendored
@@ -1,111 +0,0 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) Itay Grudev 2015 - 2020
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//
|
||||
// W A R N I N G !!!
|
||||
// -----------------
|
||||
//
|
||||
// This is a modified version of SingleApplication,
|
||||
// The original version is at:
|
||||
//
|
||||
// https://github.com/itay-grudev/SingleApplication
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef SINGLECOREAPPLICATION_P_H
|
||||
#define SINGLECOREAPPLICATION_P_H
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
|
||||
#include "singlecoreapplication.h"
|
||||
|
||||
class QLocalServer;
|
||||
class QLocalSocket;
|
||||
class QSharedMemory;
|
||||
|
||||
struct InstancesInfo {
|
||||
bool primary;
|
||||
quint32 secondary;
|
||||
qint64 primaryPid;
|
||||
char primaryUser[128];
|
||||
quint16 checksum;
|
||||
};
|
||||
|
||||
struct ConnectionInfo {
|
||||
explicit ConnectionInfo() : msgLen(0), instanceId(0), stage(0) {}
|
||||
qint64 msgLen;
|
||||
quint32 instanceId;
|
||||
quint8 stage;
|
||||
};
|
||||
|
||||
class SingleCoreApplicationPrivate : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ConnectionType : quint8 {
|
||||
InvalidConnection = 0,
|
||||
NewInstance = 1,
|
||||
SecondaryInstance = 2,
|
||||
Reconnect = 3
|
||||
};
|
||||
enum ConnectionStage : quint8 {
|
||||
StageHeader = 0,
|
||||
StageBody = 1,
|
||||
StageConnected = 2,
|
||||
};
|
||||
Q_DECLARE_PUBLIC(SingleCoreApplication)
|
||||
|
||||
explicit SingleCoreApplicationPrivate(SingleCoreApplication *ptr);
|
||||
~SingleCoreApplicationPrivate() override;
|
||||
|
||||
static QString getUsername();
|
||||
void genBlockServerName();
|
||||
void initializeMemoryBlock() const;
|
||||
void startPrimary();
|
||||
void startSecondary();
|
||||
bool connectToPrimary(const int timeout, const ConnectionType connectionType);
|
||||
quint16 blockChecksum() const;
|
||||
qint64 primaryPid() const;
|
||||
QString primaryUser() const;
|
||||
void readInitMessageHeader(QLocalSocket *socket);
|
||||
void readInitMessageBody(QLocalSocket *socket);
|
||||
static void randomSleep();
|
||||
|
||||
SingleCoreApplication *q_ptr;
|
||||
QSharedMemory *memory_;
|
||||
QLocalSocket *socket_;
|
||||
QLocalServer *server_;
|
||||
quint32 instanceNumber_;
|
||||
QString blockServerName_;
|
||||
SingleCoreApplication::Options options_;
|
||||
QHash<QLocalSocket*, ConnectionInfo> connectionMap_;
|
||||
|
||||
public slots:
|
||||
void slotConnectionEstablished();
|
||||
void slotDataAvailable(QLocalSocket*, const quint32);
|
||||
void slotClientConnectionClosed(QLocalSocket*, const quint32);
|
||||
};
|
||||
|
||||
#endif // SINGLECOREAPPLICATION_P_H
|
||||
1711
CMakeLists.txt
115
CONTRIBUTING.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# Contribution guidelines
|
||||
|
||||
Strawberry is an free and open-source project, it is possible and encouraged to participate in the development.
|
||||
You can also participate by answering questions, reporting bugs or helping with documentation.
|
||||
|
||||
|
||||
## Submitting a pull request
|
||||
|
||||
You should start by creating a fork of the Strawberry repository using the GitHub
|
||||
fork button, after that you can clone the repository from your fork.
|
||||
Replace "username" with your own.
|
||||
|
||||
|
||||
### Clone the repository
|
||||
|
||||
git clone git@github.com:username/strawberry.git
|
||||
cd strawberry
|
||||
|
||||
|
||||
### Setup the remote
|
||||
|
||||
git remote add upstream git@github.com:strawberrymusicplayer/strawberry.git
|
||||
|
||||
|
||||
### Create a new branch
|
||||
|
||||
This creates a new branch from the master branch that you use for specific
|
||||
changes.
|
||||
|
||||
git checkout -b your-branch
|
||||
|
||||
|
||||
### Stage changes
|
||||
|
||||
Once you've finished working on a specific change, stage the changes for
|
||||
a specific commit.
|
||||
|
||||
Always keep your commits relevant to the pull request, and each commit as
|
||||
small as possible.
|
||||
|
||||
git add -p
|
||||
|
||||
|
||||
### Commit changes
|
||||
|
||||
git commit
|
||||
|
||||
|
||||
### Commit messages
|
||||
|
||||
The first line should start with the name of the class that is changed
|
||||
followed by a colon then a short explanation of the commit.
|
||||
Don't use a trailing period after the first line.
|
||||
If this change affects more than one class, omit the class name and write a
|
||||
more general message.
|
||||
|
||||
You only need to include a main description (body) for larger changes
|
||||
where the one line is not enough to describe everything.
|
||||
The main description starts after two newlines, it is normal prose and
|
||||
should use normal punctuation and capital letters where appropriate.
|
||||
It should explain exactly what's changed, why it's changed,
|
||||
and what bugs were fixed.
|
||||
|
||||
An example of the expected format for git commit messages is as follows:
|
||||
|
||||
```
|
||||
StretchHeaderView: Set default section size
|
||||
|
||||
As of Qt 6.6.1, style changes are resetting the column sizes. To prevent this, we set a default section size.
|
||||
|
||||
Fixes #1328
|
||||
```
|
||||
|
||||
|
||||
### Push the changes to GitHub
|
||||
|
||||
Once you've finished working on the changes, push the branch
|
||||
to the Git repository and open a new pull request.
|
||||
|
||||
|
||||
git push origin your-branch
|
||||
|
||||
|
||||
### Update your fork's master branch
|
||||
|
||||
git checkout master
|
||||
git pull --rebase origin master
|
||||
git fetch upstream
|
||||
git merge upstream/master
|
||||
git push origin master
|
||||
|
||||
|
||||
### Update your branch
|
||||
|
||||
git checkout your-branch
|
||||
git fetch upstream
|
||||
git rebase upstream/master
|
||||
git push origin your-branch --force-with-lease
|
||||
|
||||
|
||||
### Rebase your branch
|
||||
|
||||
If you need fix any issues with your commits, you need to rebase your
|
||||
branch to squash any commits, or to change the commit message.
|
||||
|
||||
git checkout your-branch
|
||||
git log
|
||||
git rebase -i commit_sha~
|
||||
git push origin your-branch --force-with-lease
|
||||
|
||||
|
||||
### Delete your fork
|
||||
|
||||
If you do not plan to work more on Strawberry, please delete your fork from GitHub
|
||||
once the pull requests are merged.
|
||||
678
Changelog
@@ -2,7 +2,556 @@ Strawberry Music Player
|
||||
=======================
|
||||
ChangeLog
|
||||
|
||||
1.0.0:
|
||||
Version 1.2.1-rc1 (2024.11.16):
|
||||
|
||||
This release features major restructuring of the codebase, moving source files,
|
||||
rewriting CMake build files, dropping Qt 5 support, external tagreader,
|
||||
and dropping some unmaintained parts such as VLC.
|
||||
|
||||
Bugfixes:
|
||||
|
||||
* Fixed playback of CUE continuing to play from the same file after the song has finished playing (#1568).
|
||||
* Fixed updating collection song sort text when disc is changed.
|
||||
* Fixed current playing file left open when the next track errored (#1582).
|
||||
* Fixed filter search not finding song containing uppercase "A" (#1599).
|
||||
* Fixed crash when removing album from playlist when using shuffle albums (#1588).
|
||||
* Fixed IDv3 MBID's tags with multiple entries being ignored.
|
||||
* Fixed crash when enabling Tidal, Spotify, Qobuz or Subsonic services.
|
||||
* Fixed passing filenames to strawberry on command line not resolving to absolute paths.
|
||||
* (macOS) Fixed program not starting for users with long usernames.
|
||||
|
||||
Enhancements:
|
||||
|
||||
* Resolve symbolic links when dragging files to the playlist to match collection song.
|
||||
* Replaced Spotify username/password with access token.
|
||||
* Require Qt 6.4 or higher and drop support for Qt 5.
|
||||
* Require TagLib 1.12 or higher.
|
||||
* Use Qt stringliterals.
|
||||
* Move gstfastspectrum to src.
|
||||
* Use standard user temp location for current album cover.
|
||||
* Removed old MacFSListener.
|
||||
* Removed external tagreader and protobuf dependency.
|
||||
* Removed VLC support.
|
||||
* Ported to Qt translation (.ts) files and removed gettext dependency.
|
||||
* Removed deprecated Gnome/Mate SettingsDaemon global shortcuts.
|
||||
|
||||
Version 1.1.3 (2024.09.21):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed gstreamer registry lookup leak in Spotify settings.
|
||||
* Fixed all songs in a CUE sheet starting playback at the zero position (#1549).
|
||||
* Fixed playback going to pause and back to play on song change.
|
||||
* Fixed Genius Lyrics login not working (#1554).
|
||||
* Fixed slow collection filter search.
|
||||
|
||||
Version 1.1.2 (2024.09.12):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed Tidal Open API cover provider to only login when needed instead of on startup.
|
||||
* Fixed KDE added keyboard accelerator characters (ampersands) appearing in sidebar (#1400, #1389, #1476).
|
||||
* Fixed KDE added keyboard accelerator characters (ampersands) appearing when editing playlist name (#1499).
|
||||
* Fixed collection "Search for this" adding prefix without value (#1510).
|
||||
* Fixed play (-p) command line option not working on startup (#1465).
|
||||
* Fixed scan transaction being started when "Update the collection when Strawberry starts" option is unchecked (#1469)
|
||||
* Fixed Spotify bitrate being limited 128kbit/s.
|
||||
* Fixed Spotify returning too many artists and albums.
|
||||
* Fixed manually switching Spotify songs blocking UI.
|
||||
* Fixed analyzer not being set.
|
||||
* Fixed context top text being updated causing selected text to be unselected.
|
||||
* Fixed filter search to use filename for songs with empty title.
|
||||
* Fixed missing developer in Appstream appdata file.
|
||||
* Fixed MPRIS2 DesktopEntry to return desktop file entry without ".desktop" (#1516)
|
||||
* Fixed WavPack .wvc accepted as valid audio files (#1525).
|
||||
* Fixed dynamic playlist controls not following system colors (#1483).
|
||||
* Fixed freeze on playlist right click (#1478).
|
||||
* Fixed copying songs to a iPod device keeping too many files open (#1527).
|
||||
* Fixed MBIDs from MP4 being parsed incorrectly causing ListenBrainz errors (#1531).
|
||||
* Fixed playlist sorting after filename (#1538).
|
||||
|
||||
Enhancements:
|
||||
* Improved volume adjustment and track seeking using touchpad (#1498).
|
||||
* Use own thread for lyrics parsing.
|
||||
* Added url and filename columns to collection and playlist filter search.
|
||||
* (macOS) Added Spotify.
|
||||
|
||||
Version 1.1.1 (2024.07.22):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed compilation songs being split into different albums when using album grouping.
|
||||
* Fixed adding playlist columns not working when stretch mode is disabled (#1085).
|
||||
* Fixed resetting playlist columns.
|
||||
* Fixed adding songs to playlist adding all songs instead of filtered songs.
|
||||
* Fixed collection filter matching entire text instead of individual words.
|
||||
|
||||
Enhancements:
|
||||
* Use same code for collection and playlist filter search.
|
||||
|
||||
Version 1.1.0 (2024.07.14):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed crash when pressing CTRL + C (#1359).
|
||||
* Pass on scroll events to page in settings to avoid changing settings when scrolling with mouse (#1380).
|
||||
* Fixed misredered playlist search field with Wayland using scaling (#1255).
|
||||
* Fixed Azlyrics lyrics provider because of website changes.
|
||||
* Fixed Musixmatch lyrics provider because of website changes.
|
||||
* Fixed application exiting when closing file dialog (#1401).
|
||||
* Fixed playlist shuffle randomness (#707).
|
||||
* Fixed playlist shuffle order always the same when restarting playback (#1381).
|
||||
* Fixed dynamic random mix not always ignoring shuffle and repeat mode (#1366).
|
||||
* Fixed manual shuffle while playing not setting current song to new index (##1353).
|
||||
* Fixed volume sync with PA when output is set to auto (#1123).
|
||||
* Fixed mpris:trackid type with KDE 6 (#1397).
|
||||
* Fixed open in file manager feature not handling missing XDG_DATA_DIRS variable.
|
||||
* Fixed collection pixmap disk cache and moodbar cache with newer Qt versions.
|
||||
* Fixed reading common metadata CUE's with multiple files (#1463).
|
||||
* Fixed playlist header stretch mode to only resize the right column of the column being resized.
|
||||
* Fixed adding columns to playlist header not working when not using stretch mode (#1085).
|
||||
* Fixed severe memory leak (!) in context album cover fading (#1464).
|
||||
* Separate albums by different artist in album groupings (#1276).
|
||||
* Removed -new-window parameter from dolphin command for open in file manager (#1412).
|
||||
* Only use playbin3 with GStreamer 1.24 and higher, not with GStreamer 1.22 or lower.
|
||||
* (macOS/Windows) Fixed dash and hls streaming, plugins were missing.
|
||||
* (Windows) Fixed incorrect colors in smart playlist wizard with Fusion in dark mode (#1399).
|
||||
* (Windows) Fixed update window blocking sponsor window on startup.
|
||||
|
||||
Enhancements:
|
||||
* Improve error messages when connecting and copying to devices.
|
||||
* Allow enter to be used with multiselection to add songs to playlist (#1360)
|
||||
* Add song progress to taskbar using D-Bus.
|
||||
* Use API to receive Radio Paradise channels.
|
||||
* Added button for fetching lyrics to tag editor (#1391).
|
||||
* Added option not to skip "A", "An" and "The” when sorting artist names in collection (#1393).
|
||||
* Improved album and title disc, remastered, etc matching and stripping (#1387).
|
||||
* Save volume to settings when adjusting (#1272).
|
||||
* Resolve song from collection using track with Cue in XSPF (#1181).
|
||||
* Added background image to sidebar.
|
||||
* Read metadata from RIFF WAV files (#1424).
|
||||
* Use original path instead of canonical path when adding directories to the collection.
|
||||
* Only apply added/removed collection directories when settings are saved.
|
||||
* Detect and handle different text encodings when reading CUE files (#1429).
|
||||
* The collection has been rewritten and improved (model/filter/search) (#392).
|
||||
* Improve error messages from tag reader.
|
||||
* (Unix) Add experimental GStreamer pipewire support.
|
||||
* (Windows) Add experimental exclusive mode for WASAPI.
|
||||
* (Windows MSVC) Added experimental ASIO support.
|
||||
* (Windows MSVC) Add back WASAPI2.
|
||||
|
||||
New features:
|
||||
* Letras lyrics provider.
|
||||
* Open Tidal API (openapi.tidal.com) cover provider.
|
||||
* Turbine analyzer.
|
||||
* WaveRubber analyzer.
|
||||
* Spotify streaming support.
|
||||
|
||||
Removed features:
|
||||
* Removed now broken lyricsmode.com lyrics provider because of website changes.
|
||||
|
||||
Version 1.0.23 (2024.01.11):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed possible duplication of song entries after organizing (#1341).
|
||||
* Fixed possible crash when connecting devices (#1313).
|
||||
* Fixed playlist sorting of original year (#1349).
|
||||
* (macOS) Fixed crash when adding collection directory (QTBUG-120469) (#1350).
|
||||
|
||||
Enhancements:
|
||||
* Treat all stream errors as non-fatal (#1347).
|
||||
* Require KDSingleApplication 1.1.0.
|
||||
* Fix logging of restored unavailable songs.
|
||||
|
||||
Version 1.0.22 (2023.12.09):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed KDSingleApplication cmake version check.
|
||||
* Fixed KDSingleApplication Qt 5 detection (#1299).
|
||||
* Fixed timer started in wrong thread (#1302).
|
||||
* Fixed erratic seeking behaviour if buffer duration is set to zero (#1302).
|
||||
* Fixed SCollection related crash on exit with Qt 5 (#1316).
|
||||
* Fixed track about to end related crash on playback failure (#1332).
|
||||
* Fixed playlist column widths not remembered if stretch mode is off with Qt 6.6.1 and higher (#1328).
|
||||
* (Windows) Properly handle silent uninstall (#1323).
|
||||
|
||||
Enhancements:
|
||||
* Increase thread priority for playback threads.
|
||||
* Allow drag and drop of songs to favorite playlists.
|
||||
|
||||
Version 1.0.21 (2023.10.21):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed seekbar position resetting to zero before showing actual position when seeking.
|
||||
* Fixed compressed files showing up in collection (#1274).
|
||||
* Fixed connecting devices (#1288).
|
||||
* Fixed device schema missing ebur128 fields.
|
||||
* Fixed collection search by tag not working with space between colon and search term (#1290).
|
||||
* Fixed seeking when 5 seconds is remaining of the song resetting position to beginning (#1258).
|
||||
* Fixed intermittent crash when seeking with Auto as output (#1123).
|
||||
* (Windows) Fixed playlist header colors in dark mode (#1275).
|
||||
|
||||
Enhancements:
|
||||
* Support using system KDSingleApplication when available.
|
||||
* Improved lyrics matching.
|
||||
* (macOS) Fully codesign binaries and DMG.
|
||||
|
||||
Version 1.0.20 (2023.09.24):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed appdata validation.
|
||||
|
||||
Version 1.0.19 (2023.09.24):
|
||||
|
||||
Bugfixes:
|
||||
* Use shared pointers for objects to fix potential crashes on exit (#1239).
|
||||
* Fixed smart playlist search not matching unrated songs (#1244).
|
||||
* Fixed reading FMPS_Playcount for MP3 ID3v2 tags (#1248).
|
||||
* Always stop playing after 100 errors to prevent flooding the error dialog (#1220).
|
||||
* Fixed volume going to 100% when decreasing volume beyond zero (#1262).
|
||||
* Fixed error dialog sometimes showing empty.
|
||||
* (Windows) Removed broken volume sync (#1220).
|
||||
* (Windows) Fixed shuttering / choppy audio (#1227).
|
||||
* (macOS) Fixed missing search bars (#1221).
|
||||
|
||||
Enhancements:
|
||||
* Add Mpris2 property to read/write rating (#1246).
|
||||
* Capitalize playlist column names (#1264).
|
||||
* Added lyrics from songlyrics.com, azlyrics.com, elyrics.net and lyricsmode.com.
|
||||
* (Windows) Add gst-play-1.0.exe for debugging purposes.
|
||||
|
||||
New features
|
||||
* Support performing song loudness analysis using `libebur128` (#1216).
|
||||
* Support song playback loudness normalization, as per EBU R 128 (#1216).
|
||||
|
||||
Other:
|
||||
* Removed last.fm HTTPS workaround and GnuTLS dependency
|
||||
* Removed broken lyrics.com lyrics provider.
|
||||
* (Windows) Use DirectSound as default sink.
|
||||
* (Windows) Remove WASPI2 plugin because of GStreamer bug.
|
||||
|
||||
Version 1.0.18 (2023.07.02):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed reading disc from QObuz songs (#1168).
|
||||
* Fixed volume being reset on playback with PulseAudio (#1174).
|
||||
* Fixed <br> tags in SQL query error message.
|
||||
* Fixed compile with Qt 6 without XCB (QX11Application).
|
||||
* Fixed smart playlist editor not properly loading search terms (#1172).
|
||||
* Fixed use of fixed icon for playlist favorite star icon (#1178).
|
||||
* Possible fix for collection thumbnails using disk cache having identical covers for albums with hashtag (#) in the album title (#1183).
|
||||
* Fixed listenbrainz scrobbling for songs with multiple artist mbids.
|
||||
* Fixed listenbrainz scrobbling for songs without duration.
|
||||
* Fixed gapless playback sometimes not working.
|
||||
* Fixed writing PNG images as embedded covers (#1209).
|
||||
* Fixed greyscale album covers not working in OSD D-Bus (#1205).
|
||||
* Fixed collection thumbnail disk cache with Qt 6.5.1 and newer.
|
||||
* Fixed moodbar disk cache with Qt 6.5.1 and newer.
|
||||
* Fixed playlist edit tag F2 shortcut only working for title tag (#1210).
|
||||
* Append number to filename if the destination file already exist when transcoding audio (#1200).
|
||||
* Fixed abseil linking issues with protobuf 1.22.0 and newer.
|
||||
* (macOS) Fixed "Show this message" checkbox having no affect on Rosetta warning dialog (#1180).
|
||||
* (macOS) Disable unused D-Bus.
|
||||
* (Windows) Fixed command line options not working with diacritics (#1191).
|
||||
* (Windows) Fixed issue with saving album covers in album directory being saved in temp directory instead.
|
||||
* (Windows) Fixed crash when trying a play a song which doesn't exist, gstreamer issue #1683 (#1214).
|
||||
|
||||
Enhancements:
|
||||
* Reduce memory overhead with album cover handling (#1046).
|
||||
* Improved listenbrainz error handling.
|
||||
* Show error dialog for listenbrainz errors similar to last.fm/libre.fm.
|
||||
* Reduce NetworkAccessManager instances.
|
||||
* Replace SingleApplication with KDSingleApplication.
|
||||
* Require Qt 5.12 or higher.
|
||||
* Add new database fields for art_embedded and art_unset.
|
||||
* Rewrite album cover loader.
|
||||
* Move cover filename settings from collection to covers settings.
|
||||
* Add setting to set priorities for album cover types.
|
||||
* Add rating filtering to playlist search (#1212).
|
||||
* (Windows|MSVC) Add WSAPI2 plugin.
|
||||
|
||||
Version 1.0.17 (2023.03.29):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed over-sized context album cover with device pixel ratio higher than 1.0 (#1166).
|
||||
* Fixed playing widget fading from a blurry previous cover with device pixel ratio higher than 1.0.
|
||||
* Made playlist source icon, album cover manager and OSD pretty cover respect device pixel ratio.
|
||||
|
||||
Version 1.0.16 (2023.03.27):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed lyrics from Musixmatch.
|
||||
* Fixed possible file corruption when saving both tags and embedded cover using the tag editor (#1158).
|
||||
* Fixed compile without GStreamer.
|
||||
* Fixed context and playing now album art rendering on High DPI displays (#1161).
|
||||
* Fixed setting source properties (device, user-agent, ssl-strict) with GStreamer 1.22 (playbin3) and higher (#1148).
|
||||
* Fixed rescan songs feature not ignoring mtime.
|
||||
* Search lyrics by artist instead of album artist by default.
|
||||
|
||||
Code improvements:
|
||||
* Replace use of deprecated QSqlDatabase::exec().
|
||||
|
||||
Added features:
|
||||
* Added backend setting for strict SSL mode.
|
||||
* Read AcoustID and MusicBrainz tags.
|
||||
* Submit MusicBrainz tags with ListenBrainz.
|
||||
|
||||
Version 1.0.15 (2023.03.04):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed playlist column showing invalid last played date for streams.
|
||||
* Fixed crash when the audio bin failed to initialize (#1123, #1133).
|
||||
* Fixed duplicated filename when organizing files using dot in the filename (#1136).
|
||||
* Fixed tag inline editing for streams (#1130).
|
||||
* Fixed resetting play statistics using tag edit dialog (#1124).
|
||||
* Fixed compilation songs not showing if group by was set to other than (Album) Artist / Album (#1140).
|
||||
|
||||
Enhancements:
|
||||
* Added lyrics from stands4 (lyrics.com).
|
||||
* Added Sonogram analyzer.
|
||||
* Use GStreamer playbin3 with GStreamer 1.22.0 and higher.
|
||||
|
||||
Code improvements:
|
||||
* Made use of C++11 enum class where possible.
|
||||
* Use new QNativeIpcKey based QSharedMemory constructor with Qt 6.6 and higher.
|
||||
|
||||
Version 1.0.14 (2023.01.13):
|
||||
|
||||
Bugfixes:
|
||||
* Fix initial volume not set when using Auto as output (#1104).
|
||||
* Fix saving moodbar if the URL contains host, ie.: UNC paths for SMB (#1101).
|
||||
* Fix CollectionBackendTest compile error (#1100).
|
||||
* Remove explicitly enabling debug messages (#1106).
|
||||
|
||||
Version 1.0.13 (2023.01.09):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed volume synchronization leading to infinite loop resulting in crash when adjusting volume while playing (#1089).
|
||||
* Fixed incorrect volume.
|
||||
* Fixed collection organizing incorrectly handling slashes inside {} brackets for variables (#1091).
|
||||
* Fixed saving relative playlists to non-existing playlist files (#1092).
|
||||
* Fixed intermittent crash on collection model query (#1095).
|
||||
* Require system icons for fancy tabbar and settings sidebar to be larger than 22x22 (#1084).
|
||||
|
||||
Version 1.0.12 (2023.01.02):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed crash when adjusting volume with mouse wheel (#1089).
|
||||
* Fixed playback stopping in certain cases where the next track was unavailable (#958).
|
||||
* (Windows) Apply patch for fonts too large on High DPI screen (QTBUG-108593).
|
||||
|
||||
Removed features:
|
||||
* Removed appearance settings for changing palette colors, it was never properly implemented.
|
||||
|
||||
Version 1.0.11 (2022.12.30):
|
||||
|
||||
Bugfixes:
|
||||
* Capitalize GLib application name so it appears nicely in GNOME and PulseAudio Volume Control (#1066).
|
||||
* Fixed missing application icon for PulseAudio Volume Control (#1066).
|
||||
* Ignore errors for missing albums when updating Tidal collection if there are results (#1061).
|
||||
* Only run periodic collection scan when moitoring collection setting is on.
|
||||
* Fixed an edge case where the context headline text was being cut short (#1067).
|
||||
* Made "Show in file browser" support SpaceFM filemanager (#1073).
|
||||
* Fixed incorrect tab order in edit tag dialog (#1075).
|
||||
* Changed "FMPS_PlayCount" to "FMPS_Playcount" when saving tag (#1074).
|
||||
* Fixed compilation tag read and write for MP4 (#1076).
|
||||
* Removed incorrect use of "TPE1" for performer when reading ID3 tags (#1076).
|
||||
* Disable tag fields for unsupported tags in tag editor.
|
||||
* Don't allow organizing files without unique tags (track or title) for filename (#1077).
|
||||
* Don't remove disc from album title when creating cover hash to allow different covers for each disc on an album (#1069).
|
||||
* Fixed incorrect relative paths for song filenames when saving playlists if the saved playlist location is a symablic link to the song filename (#1071).
|
||||
* Scrobble "Various Artists" as album artist (#1082).
|
||||
|
||||
Enhancements:
|
||||
* Use system volume instead of own software volume when available (#1037).
|
||||
* Improved Tidal and Qobuz support with timed requests.
|
||||
* Support MPRIS2 xesam:userRating.
|
||||
|
||||
Version 1.0.10 (2022.10.21):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed "Could not open settings file for writing: No such file or directory" error before settings file is created.
|
||||
* Fixed visual glitch on currently playing track (#1051).
|
||||
* Fixed "Unknown error" on Tidal search (#1047).
|
||||
* Fixed incomplete lyrics from Genius.
|
||||
* Fixed icons not showing in the file view on some systems (#1024).
|
||||
* Fixed issues with context and playing widget stopping when using VLC (#1054).
|
||||
* (macOS) Fixed search field related crash when playlist toolbar is turned off.
|
||||
|
||||
Enhancements:
|
||||
* Fixed narrowing conversions in connects.
|
||||
* Fixed casts from QByteArray.
|
||||
* Removed subdir for generated dbus files
|
||||
* Removed use of fixed font in context (#1040).
|
||||
* Improve Musixmatch lyrics search.
|
||||
|
||||
Version 1.0.9 (2022.09.03):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed parsing album title from radio stream metadata (#1023).
|
||||
* (macOS) Fixed Strawberry not starting, incorrect rpath for libgcc_s.1.1.dylib (#1025).
|
||||
* (macOS) Fixed HTTP streaming.
|
||||
|
||||
Version 1.0.8 (2022.08.29):
|
||||
|
||||
Bugfixes:
|
||||
* Fixed backslash being appended to filter text when switching playlist (#1005).
|
||||
* Fixed OSD notifications service registering taking too long to timeout when not available.
|
||||
* Fixed radio stream added twice when double-clicked (#1015).
|
||||
* Fixed translating undo and redo buttons (#1017).
|
||||
|
||||
Enhancements:
|
||||
* Use ICU instead of iconv to transliterate characters for filenames.
|
||||
* Make separating albums by grouping tag optional in collection group by album.
|
||||
* Added support for video game music formats VGM and SPC.
|
||||
* Added setting for explicitly turning on HTTP/2 for streaming. Strawberry will set the
|
||||
libsoup SOUP_FORCE_HTTP1 environment variable when the HTTP/2 is not checked (#1016).
|
||||
* (Windows|MSVC) Install Visual C++ runtime redistributable automatically in installer.
|
||||
|
||||
Version 1.0.7 (2022.07.25)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed checking file extension case-insensitive when loading and saving playlists.
|
||||
* Fixed reading and saving rating with TagParser.
|
||||
* (macOS/Windows) Fixed playlist column alignment. Applied patch for Qt bug QTBUG-103576 (#999).
|
||||
* (Windows|MinGW) Fixed HLS streaming.
|
||||
* (Windows|MSVC) Fixed MP3 encoding.
|
||||
|
||||
Enhancements
|
||||
* Added option for selecting file extension when saving all playlists.
|
||||
|
||||
Version 1.0.6 (2022.07.17)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed certain albums not added to playlist in correct track order from search for Tidal and QObuz.
|
||||
* Fixed songs not added to playlist in numeric order when added from file view with right click (#977).
|
||||
* Fixed "Stop after this track" graying out next track in dynamic mode (#912).
|
||||
* Fixed a gstreamer caps leak when transcoding songs.
|
||||
* Fixed errors in translation files (#994).
|
||||
|
||||
Enhancements
|
||||
* Add songs to the collection even when they have invalid ctime or mtime.
|
||||
* Made ListenBrainz scrobbler respect "Prefer album artist" option (#989).
|
||||
* Send track duration, number, player name and version when scrobbling to ListenBrainz (#995).
|
||||
* (macOS) Added missing HLS streaming plugin.
|
||||
|
||||
Version 1.0.5 (2022.06.10)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed smart playlist filetype search.
|
||||
* Fixed Radio Paradise URLs to use HTTPS instead of HTTP.
|
||||
* Fixed horizontal scrolling not affecting currently playing track (#952).
|
||||
* Fixed keep running in the background when window is closed with Wayland (#964).
|
||||
* Fixed percent-encoding of URLs when loading and saving XSPF playlists (#821).
|
||||
* Fixed fancy tabbar context menu showing on right clicks outside of tabbar when a song is playing.
|
||||
* Fixed possible duplicating songs in the database when moving songs to the collection using the organize feature.
|
||||
* (Windows|MSVC) Fixed moodbar fftw3 crash with (older) CPU's that does not support AVX2 (#944).
|
||||
* (Windows|MSVC) Fixed using libiconv for converting characters when organizing files like with MinGW.
|
||||
|
||||
Enhancements
|
||||
* Show more details in error dialog on GStreamer errors (#958).
|
||||
* Allow setting blur amount of playlist background image up to 100px (#939).
|
||||
* Include 128x128 icon sizes (#954).
|
||||
* Show right click copy context menu in context view on top text and lyrics (#965).
|
||||
* Improve fading between album covers in context view.
|
||||
* Added option for overwriting database playcounts in collection settings (#962).
|
||||
* Added option for disabling bar on currently playing track (#972).
|
||||
* (Debian) Added Qt 6 support to debian files and build with Qt 6 for Debian Bookworm, Ubuntu Jammy and newer.
|
||||
* (Windows|MSVC) Added libav/ffmpeg plugin.
|
||||
|
||||
Version 1.0.4 (2022.04.10)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed use-after-free memory in ALSA PCM device finder.
|
||||
* Translate global shortcuts.
|
||||
* (Windows) Fixed registering 0-9 numpad keys in global shortcuts.
|
||||
|
||||
Enhancements
|
||||
* Added save all playlists action.
|
||||
* (Windows) Made updater support both MSVC and MinGW.
|
||||
* (Windows) Added HLS support.
|
||||
|
||||
Other:
|
||||
* Removed use of custom font in context.
|
||||
|
||||
Version 1.0.3 (2022.03.24)
|
||||
|
||||
Bugfixes:
|
||||
* Remove slash and backslash from filenames when saving album covers using album directory cover filenames (#903).
|
||||
* Remove playlist file-extensions from accepted audio file extensions (#909).
|
||||
* Fixed Qobuz requests only receiving the first 50 albums (#922).
|
||||
* (Windows|MinGW) Fixed streaming stopping at the end of each track. libsoup downgraded from 3.0 to 2.74.
|
||||
* (Windows|MSVC) Fixed initial database schema failure caused by CRLF line-endings in schema files.
|
||||
|
||||
New features
|
||||
* Added support for bs2b (Improved headphone listening of stereo audio records using Bauer stereophonic-to-binaural DSP) (#249).
|
||||
|
||||
Version 1.0.2 (2022.02.20)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed showing menu when clicking icon for collection and internet search tool buttons
|
||||
* Fixed ignoring devices with system mounts as defined by GIO (#410).
|
||||
* Fixed updating database when deleting songs from filesystem devices.
|
||||
* Fixed unregistered metatype when listing songs from MTP devices with Qt 6.
|
||||
* Fixed using entered password when testing Subsonic settings before pressing save (#879).
|
||||
* Fixed downloading Subsonic album covers.
|
||||
* Fixed subsonic album covers downloaded several times for each album when MD5 authentication was enabled (#885).
|
||||
* Fixed volume going to 100% when pressing volume down with MRPIS2 and global shortcuts (#884).
|
||||
* Fixed incorrect rounding when setting volume through MPRIS2 (#894).
|
||||
* Fixed delete from disk not showing up in the menu when one or more CUE songs were selected.
|
||||
* Fixed possible crashes when switching songs when fading is enabled (#890).
|
||||
* Fixed X11 global shortcuts not working unless window was in focus with Qt 6.2 and higher (#893).
|
||||
* Fixed scrobbler re-sending scrobbles to fast on error (#898).
|
||||
|
||||
Enhancements
|
||||
* Log Qt version on startup.
|
||||
* Added button for deleting existing Subsonic songs (#883).
|
||||
* Make collection watcher ignore files with "qt_temp" filename and tmp extension.
|
||||
* Require Qt 5.9 or higher.
|
||||
* Added scrollbars to edit tag dialog (#888).
|
||||
* Added advanced settings for configuring collection watcher.
|
||||
* Disable open audio CD menu when compiled without audio CD support.
|
||||
* Replaced use of deprecated QMouseEvent constructor as of Qt 6.4.
|
||||
* Replaced use of deprecated QCryptographicHash::addData overload as of Qt 6.4.
|
||||
|
||||
Removed features:
|
||||
* Removed broken "nomedia" / "nomusic" file handling.
|
||||
|
||||
Version 1.0.1 (2022.01.08)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed collection and internet search filter tool button menu arrow overlap (#796).
|
||||
* Fixed stop after this track button with Qt 6 (#795).
|
||||
* Fixed not updating the URL when songs were moved on disk when the fingerprinting feature is enabled.
|
||||
* Fixed SQL query error for songs with an invalid modification time (#815).
|
||||
* Fixed blocky rendering of the currently playing track with high resolution screens (#794).
|
||||
* Fixed incorrect playlist column filesize for radio streams.
|
||||
* Fixed deleting embedded album cover from Ogg songs.
|
||||
* Fixed parsing of Cue tracks with 1-digit minutes (#836).
|
||||
* Fixed updating of playlist summary after reloading items when adding songs from files outside of the collection (#848).
|
||||
* Fixed always saving metadata when saving playlists for Tidal, Qobuz and Subsonic songs independent of playlist setting (#851).
|
||||
* Fixed setting media shortcuts when using kglobalaccel (#849).
|
||||
* Fixed parsing of Genius lyrics when they are sometimes received in a different HTML format.
|
||||
* Fixed saving MP4 specific tags as UTF-8 (#830).
|
||||
* Fixed clearing "manually set" cover when saving album covers embedded from outside of the tag editor (#858).
|
||||
* Fixed aborting collection scan when Strawberry exists to avoid hang on exit.
|
||||
* Fixed resuming collection scan when adding a new directory after collection scan was aborted.
|
||||
* Fixed excluding hidden songs from the collection.
|
||||
* Disabled moodbar for CUE songs since they can not be supported properly (#865).
|
||||
* (Windows) Added gstreamer gstxingmux plugin to fix transcoding to MP3 (#856).
|
||||
|
||||
Enhancements:
|
||||
* Made playlist header column text elided (#801).
|
||||
* Added support for reading and writing playcounts and ratings from/to tags.
|
||||
* Added support for setting rating using the edit tag dialog.
|
||||
* Added setting to enable/disable playlist toolbar (#809).
|
||||
* Added component type, content_rating type and releases to AppStream data file (#806).
|
||||
* Removed unused "mark as listened" option in organize dialog.
|
||||
* Fixed some clazy warnings and narrowing conversions in the source code.
|
||||
* Replaced uses of macros in the source code.
|
||||
* Added a more user-friendly error message when receiving encrypted streams from Tidal (#824).
|
||||
* Added support for port-pattern entered in the device textbox when using Jack as output (#828).
|
||||
* Added Spanish (Spain) translation.
|
||||
* Added support for more CUE filenames (#835).
|
||||
* (Windows) Add gstreamer dash plugin.
|
||||
|
||||
Version 1.0.0 (2021.10.14)
|
||||
|
||||
Bugfixes:
|
||||
* Fix updating temporary metadata when reloading songs outside of the collection.
|
||||
@@ -56,12 +605,13 @@ ChangeLog
|
||||
* Add support for native global shortcuts on MATE.
|
||||
* Add radios view with channels from Radio Paradise and SomaFM.
|
||||
|
||||
0.9.3:
|
||||
|
||||
Version 0.9.3 (2021.04.18)
|
||||
|
||||
Bugfixes:
|
||||
* Fix "Show in file browser" to work with thunar.
|
||||
* Check that the clicked rating position is to the right or left of the rectangle.
|
||||
* Fix rescan when collection directory is removed and readded.
|
||||
* Fix rescan when collection directory is removed and re-added.
|
||||
* Create GLib main event loop on non-glib systems to fix stream discoverer.
|
||||
* (macOS) Fix intermittent abort on startup.
|
||||
* (macOS) Fix Tidal and Qobuz search field not showing.
|
||||
@@ -79,7 +629,8 @@ ChangeLog
|
||||
* (macOS) Make macdeployqt work with Qt 5 too.
|
||||
* (macOS) Show keep running option in behaviour settings.
|
||||
|
||||
0.9.2:
|
||||
|
||||
Version 0.9.2 (2021.03.25)
|
||||
|
||||
Bugfixes:
|
||||
* Fix marking songs available.
|
||||
@@ -90,7 +641,8 @@ ChangeLog
|
||||
* (macOS) Fix crash when opening cover manager.
|
||||
* (macOS) Fix broken Qt plugins resulting in album covers not showing.
|
||||
|
||||
0.9.1:
|
||||
|
||||
Version 0.9.1 (2021.03.13)
|
||||
|
||||
Bugfixes:
|
||||
* Fix duplicating songs in the DB when organizing songs between 2 different collection directories.
|
||||
@@ -125,7 +677,8 @@ ChangeLog
|
||||
New features:
|
||||
* Add option and support for saving embedded covers for FLAC, Ogg Vorbis, MP3 and MP4/AAC.
|
||||
|
||||
0.8.5:
|
||||
|
||||
Version 0.8.5 (2020.12.19)
|
||||
|
||||
Bugfixes:
|
||||
* Fix return type of SmartPlaylistQueryWizardPlugin::type().
|
||||
@@ -144,7 +697,8 @@ ChangeLog
|
||||
* Add command line option to play a playlist based on name.
|
||||
* Change double-click behaviour in cover manager to open fullsize cover.
|
||||
|
||||
0.8.4:
|
||||
|
||||
Version 0.8.4 (2020.11.15)
|
||||
|
||||
Bugfixes:
|
||||
* Fix preventing session logout when window is maxmimized.
|
||||
@@ -170,7 +724,8 @@ ChangeLog
|
||||
* Remove remaining uses of QTextCodec.
|
||||
* Remove Core5Compat dependency.
|
||||
|
||||
0.8.3:
|
||||
|
||||
Version 0.8.3 (2020.10.24)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed updating playing widget song details in small cover mode.
|
||||
@@ -185,7 +740,8 @@ ChangeLog
|
||||
Enhancements:
|
||||
* (Windows) Added WASAPI plugin.
|
||||
|
||||
0.8.2:
|
||||
|
||||
Version 0.8.2 (2020.10.13)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed broken transition to next song for CUE files with certain audio formats (regression since version 0.6.13).
|
||||
@@ -197,7 +753,8 @@ ChangeLog
|
||||
* Removed use of HTML in system tray icon tooltip for all desktop environments instead of just KDE and Cinnamon.
|
||||
* (Windows) Ignore "IDirectSoundBuffer_GetStatus The operation completed successfully" false error when switching device while playing.
|
||||
|
||||
0.8.1:
|
||||
|
||||
Version 0.8.1 (2020.10.09)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed engine selection in backend settings with Qt 6.
|
||||
@@ -244,14 +801,15 @@ ChangeLog
|
||||
* Added Subsonic server side scrobbling support.
|
||||
* Load thumbnails from iPods to show under device collection.
|
||||
|
||||
0.7.2:
|
||||
Version 0.7.2 (2020.08.15)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed installation directory for translations.
|
||||
* Fixed collection sorting for non-ASCII characters.
|
||||
* Fixed closing connected devices on exit.
|
||||
|
||||
0.7.1:
|
||||
|
||||
Version 0.7.1 (2020.08.15)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed incorrectly mapped global shortcuts keys "2" and "3".
|
||||
@@ -290,7 +848,8 @@ ChangeLog
|
||||
* Removed Xine engine support.
|
||||
* Removed broken imobiledevice (iPhone) support.
|
||||
|
||||
0.6.13:
|
||||
|
||||
Version 0.6.13 (2020.07.13)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed cut-off text in about dialog.
|
||||
@@ -316,7 +875,8 @@ ChangeLog
|
||||
* Fixed unit test for testing playlist model.
|
||||
* Added new unit tests for tagreader.
|
||||
|
||||
0.6.12:
|
||||
|
||||
Version 0.6.12 (2020.06.07)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed height of about dialog.
|
||||
@@ -329,7 +889,8 @@ ChangeLog
|
||||
* Sort folders added from file view.
|
||||
* Changed default collection grouping to album - disc.
|
||||
|
||||
0.6.11:
|
||||
|
||||
Version 0.6.11 (2020.05.16)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed MPRIS missing art url when playing albums with embedded cover.
|
||||
@@ -355,7 +916,8 @@ ChangeLog
|
||||
* Added album covers from Musixmatch and Spotify.
|
||||
* Added lyrics from Genius, Musixmatch and ChartLyrics.
|
||||
|
||||
0.6.10:
|
||||
|
||||
Version 0.6.10 (2020.05.01)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed Subsonic album covers not working for albums with non ASCII characters.
|
||||
@@ -386,7 +948,7 @@ ChangeLog
|
||||
* Made font and font sizes in context configurable.
|
||||
* Splitting artist and song title to the relevant metadata when artist and song title is sent as title separated by a dash in streams.
|
||||
* Added label to show collection pixmap disk cache used in settings.
|
||||
* Icreased default collection pixmap disk cache to 360.
|
||||
* Increased default collection pixmap disk cache to 360.
|
||||
|
||||
New features:
|
||||
* Added back Tidal streaming support.
|
||||
@@ -395,7 +957,8 @@ ChangeLog
|
||||
Removed features:
|
||||
* Removed Phonon engine support.
|
||||
|
||||
Version 0.6.9:
|
||||
|
||||
Version 0.6.9 (2020.03.09)
|
||||
|
||||
BugFixes:
|
||||
* Fixed playlist metadata updating interfering with manual tag editing.
|
||||
@@ -427,7 +990,8 @@ Version 0.6.9:
|
||||
* Tidal support (No agreement).
|
||||
* QObuz support (No agreement).
|
||||
|
||||
Version 0.6.8:
|
||||
|
||||
Version 0.6.8 (2020.01.05)
|
||||
|
||||
* Fixed stuck tabbar and collection GUI with some themes.
|
||||
* Fixed possible crashes related to QProxyStyle.
|
||||
@@ -444,14 +1008,15 @@ Version 0.6.8:
|
||||
* (macOS) Fixed filesystem watcher to correctly pick up changed collection directories.
|
||||
* (Windows) Fixed translations not being included.
|
||||
|
||||
Version 0.6.7:
|
||||
|
||||
Version 0.6.7 (2019.11.27)
|
||||
|
||||
* Fixed crash when cancelling scrobbler authentication
|
||||
* Fixed "Double clicking a song in the playlist" behaviour setting
|
||||
* Fixed "Pressing Previous in player" behaviour setting
|
||||
* Fixed updating compilations where there are spaces or special characters in filenames
|
||||
* Fixed cases where songs were stuck in "Various Artists" because not all songs in
|
||||
the same compilation was removed from the model before readded with actual artist.
|
||||
the same compilation was removed from the model before re-added with actual artist.
|
||||
* Fixed a bug when importing playlists where metadata was reset
|
||||
* Fixed scrobbler to also scrobble songs without album title
|
||||
* Fixed text for replay gain setting not loading in backend setting
|
||||
@@ -461,7 +1026,8 @@ Version 0.6.7:
|
||||
* Removed left click on analyzer to popup menu
|
||||
* (Windows) Added killproc executable to terminate running process before uninstalling
|
||||
|
||||
Version 0.6.6:
|
||||
|
||||
Version 0.6.6 (2019.11.09)
|
||||
|
||||
* Fixed lowercased album artist in playlist column
|
||||
* Fixed compiling with different optional features turned off
|
||||
@@ -479,7 +1045,8 @@ Version 0.6.6:
|
||||
* Added option to automatically select current playing track
|
||||
* (Windows) Added support for WASAPI
|
||||
|
||||
Version 0.6.5:
|
||||
|
||||
Version 0.6.5 (2019.09.30)
|
||||
|
||||
* Fixed scrobbler not to send scrobbles multiple times when metadata is updated
|
||||
* Fixed Listenbrainz scrobbler not don't send "various artists" as album artist
|
||||
@@ -488,7 +1055,8 @@ Version 0.6.5:
|
||||
* Fixed OSD pretty positioning on Windows on screens with negative geometry
|
||||
* Fixed appdata file to pass full validation
|
||||
|
||||
Version 0.6.4:
|
||||
|
||||
Version 0.6.4 (2019.09.25)
|
||||
|
||||
* Added setting for fancy tabbar background color
|
||||
* Added setting to make marking songs unavailable optional
|
||||
@@ -515,18 +1083,21 @@ Version 0.6.4:
|
||||
* Fixed restoring to original window size when restoring from system tray
|
||||
* Updated 3rdparty taglib
|
||||
|
||||
Version 0.6.3:
|
||||
|
||||
Version 0.6.3 (2019.08.05)
|
||||
|
||||
* Fixed crash when using internet services.
|
||||
* Fixed musicbrainz tagfetcher only showing 1 result per song.
|
||||
* Fixed collection watcher to unwatch deleted directories.
|
||||
* Added "album - disc" grouping.
|
||||
|
||||
Version 0.6.2:
|
||||
|
||||
Version 0.6.2 (2019.08.03)
|
||||
|
||||
* Disabled fatal error for FTS5 cmake test.
|
||||
|
||||
Version 0.6.1:
|
||||
|
||||
Version 0.6.1 (2019.08.03)
|
||||
|
||||
* Compare artist and album case-insensitive when generating score for album covers.
|
||||
* Fixed broken return value of sendMessage() in SingleApplication causing application to be started twice.
|
||||
@@ -572,11 +1143,13 @@ Version 0.6.1:
|
||||
* Fixed certain cases where the playing widget gets stuck when switching fast between context and other widgets.
|
||||
* Removed ChartLyrics provider (service have been down for a long time).
|
||||
|
||||
Version 0.5.5:
|
||||
|
||||
Version 0.5.5 (2019.05.05)
|
||||
|
||||
* Fixed Tidal API url
|
||||
|
||||
Version 0.5.4:
|
||||
|
||||
Version 0.5.4 (2019.05.05)
|
||||
|
||||
* Changed description for offline mode scrobbling for less confusion
|
||||
* Fixed scrobbler to not send "playing now" when in offline mode
|
||||
@@ -607,7 +1180,8 @@ Version 0.5.4:
|
||||
* Fixed and improved snap including upgrading to core18 and adding proper alsa support
|
||||
* Fixed resume playback on startup not working for other than the first playlist
|
||||
|
||||
Version 0.5.3:
|
||||
|
||||
Version 0.5.3 (2019.03.02)
|
||||
|
||||
* Changed default tagging to albumartist in organise dialog
|
||||
* Removed support for older taglib in tagreader
|
||||
@@ -647,7 +1221,8 @@ Version 0.5.3:
|
||||
* Added group by format
|
||||
* Fixed gstreamer leaks
|
||||
|
||||
Version 0.5.2:
|
||||
|
||||
Version 0.5.2 (2019.01.26)
|
||||
|
||||
* Added error handling and message for URL handler
|
||||
* Added SingleCoreApplication secondary check
|
||||
@@ -664,7 +1239,8 @@ Version 0.5.2:
|
||||
* Added option to copy album cover in organise dialog (filesystem and libgpod devices)
|
||||
* Added raise() to make sure window is on top when strawberry is started twice
|
||||
|
||||
Version 0.5.1:
|
||||
|
||||
Version 0.5.1 (2019.01.12)
|
||||
|
||||
* Added scrobbler with support for Last.fm, Libre.fm and ListenBrainz
|
||||
* Fixed key up causing playback to reset
|
||||
@@ -695,7 +1271,8 @@ Version 0.5.1:
|
||||
* Added debian copyright file
|
||||
* Fixed some compile errors
|
||||
|
||||
Version 0.4.2:
|
||||
|
||||
Version 0.4.2 (2018.11.28)
|
||||
|
||||
* Updated AppStream data file to newer specifications
|
||||
* Fixed Deezer engine to use quality setting
|
||||
@@ -709,7 +1286,8 @@ Version 0.4.2:
|
||||
* (Windows) Corrected uninstalled files on x64 installer
|
||||
* (macOS) Fixed poor performance
|
||||
|
||||
Version 0.4.1:
|
||||
|
||||
Version 0.4.1 (2018.11.01)
|
||||
|
||||
* Fixed crash in analyzer
|
||||
* Fixed trying to use systray even if the desktop had no systray
|
||||
@@ -727,11 +1305,13 @@ Version 0.4.1:
|
||||
* Added AppStream data file
|
||||
* Fixed compiling with Qt 5 versions of system QtSingleApplication and Qxt library
|
||||
|
||||
Version 0.3.3:
|
||||
|
||||
Version 0.3.3 (2018.09.24)
|
||||
|
||||
* Fixed Tidal login
|
||||
|
||||
Version 0.3.2:
|
||||
|
||||
Version 0.3.2 (2018.09.24)
|
||||
|
||||
* Fixed search error not shown in Tidal search
|
||||
* Added URL handler for Tidal, now retrieving URL's when playing instead of when searching
|
||||
@@ -743,7 +1323,8 @@ Version 0.3.2:
|
||||
* Added encoding of Tidal token in the source code
|
||||
* Added encoding of Tidal password in the configuration
|
||||
|
||||
Version 0.3.1:
|
||||
|
||||
Version 0.3.1 (2018.09.15)
|
||||
|
||||
* Added new lyrics provider with lyrics from AudD and API Seeds
|
||||
* New improved context widget with albums and lyrics
|
||||
@@ -765,7 +1346,8 @@ Version 0.3.1:
|
||||
* Added support for reading/writing lyrics to tags
|
||||
* Fixed saving tags (APE) for WavPack files
|
||||
|
||||
Version 0.2.1:
|
||||
|
||||
Version 0.2.1 (2018.07.05)
|
||||
|
||||
* Fixed crash with newer Qt
|
||||
* Fixed setting output/device for Xine and VLC backend
|
||||
@@ -775,19 +1357,23 @@ Version 0.2.1:
|
||||
* Fixed device selection on macOS
|
||||
* Added xine on to windows build
|
||||
|
||||
Version 0.1.6:
|
||||
|
||||
Version 0.1.6 (2018.06.07)
|
||||
* Fixed crash on exit caused by NVIDIA driver
|
||||
* Fixed PulseAudio device selection
|
||||
* Improvements to device selection
|
||||
|
||||
Version 0.1.5:
|
||||
|
||||
Version 0.1.5 (2018.05.16)
|
||||
* Makefile fixes for building
|
||||
|
||||
Version 0.1.4:
|
||||
* Fixed compliation with clang compiler
|
||||
|
||||
Version 0.1.4 (2018.05.14)
|
||||
* Fixed compilation with clang compiler
|
||||
* This release is mainly to get it working on openbsd and freebsd.
|
||||
|
||||
Version 0.1.3:
|
||||
|
||||
Version 0.1.3 (2018.05.12)
|
||||
* Audio file detection by content
|
||||
* Added builtin taglib to 3rdparty to support detecting audio by content instead of just file extension
|
||||
* Removed unneeded qsqlite from 3rdparty
|
||||
@@ -795,7 +1381,8 @@ Version 0.1.3:
|
||||
* Replaced incorrect DLL libgstdirectsoundsink.dll (from gst 1.12.4) instead of libgstdirectsound.dll (from gst 1.14.0) for windows build
|
||||
* Fixed git versioning
|
||||
|
||||
Version 0.1.2:
|
||||
|
||||
Version 0.1.2 (2018.05.02)
|
||||
* Fixed playback of WavPack files
|
||||
* Fixed musicbrainz tagfetcher
|
||||
* Use common regex (Song::kCoverRemoveDisc) for removing Disc/CD from album
|
||||
@@ -805,5 +1392,6 @@ Version 0.1.2:
|
||||
* Fixed problems with windows build missing some DLL's, only supplying required gstreamer-plugins now
|
||||
* Removed redundant code
|
||||
|
||||
Version 0.1.1:
|
||||
|
||||
Version 0.1.1 (2018.04.07)
|
||||
* Initial release
|
||||
|
||||
74
README.md
@@ -1,4 +1,4 @@
|
||||
:strawberry: Strawberry Music Player [](https://github.com/strawberrymusicplayer/strawberry/actions)
|
||||
:strawberry: Strawberry Music Player [](https://github.com/strawberrymusicplayer/strawberry/actions)
|
||||
=======================
|
||||
[](https://github.com/sponsors/jonaski)
|
||||
[](https://patreon.com/jonaskvinge)
|
||||
@@ -11,32 +11,36 @@ Strawberry is a music player and music collection organizer. It is a fork of Cle
|
||||
Resources:
|
||||
|
||||
* Website: https://www.strawberrymusicplayer.org/
|
||||
* Wiki: https://wiki.strawberrymusicplayer.org/
|
||||
* Forum: https://forum.strawberrymusicplayer.org/
|
||||
* Github: https://github.com/strawberrymusicplayer/strawberry
|
||||
* Buildbot: https://buildbot.strawberrymusicplayer.org/
|
||||
* Latest builds: https://builds.strawberrymusicplayer.org/
|
||||
* openSUSE buildservice: https://build.opensuse.org/package/show/home:jonaski:audio/strawberry
|
||||
* Ubuntu PPA: https://launchpad.net/~jonaski/+archive/ubuntu/strawberry
|
||||
* Ubuntu Unstable PPA: https://launchpad.net/~jonaski/+archive/ubuntu/strawberry-unstable
|
||||
* Translations: https://translate.zanata.org/iteration/view/strawberry/master
|
||||
* Translations: https://crowdin.com/project/strawberrymusicplayer/
|
||||
|
||||
### :bangbang: Opening an issue:
|
||||
### :bangbang: Opening an issue
|
||||
|
||||
* Read the FAQ: https://wiki.strawberrymusicplayer.org/wiki/FAQ
|
||||
* Search for the issue to see if it is already solved, or if there is an open issue for it already. If there is an open issue already, you can comment on it if you have additional information that could be useful to us.
|
||||
* For technical problems, questions and feature requests please use our forum on https://forum.strawberrymusicplayer.org/ that is better suited for discussion. It also better allows answers from the community instead of just the developers on GitHub.
|
||||
* For technical problems, discussion, questions and feature suggestions use the forum (https://forum.strawberrymusicplayer.org/) instead. The forum is better suited for discussion.
|
||||
* We do not take feature requests from users on GitHub. Any issues related to feature requests will be closed. This does not necessarily mean that we won't add new features, but we don't have time to take feature requests or answer questions about new features from users. It is still possible to suggest or discuss new features on the forum (https://forum.strawberrymusicplayer.org/).
|
||||
* We do not maintain the Flatpak package. Do not report issues related to Flatpak unless the issue can be reproduced with a native package, use Flatpak support instead https://flatpak.org/about/
|
||||
|
||||
### :moneybag: Sponsoring:
|
||||
### :moneybag: Sponsoring
|
||||
|
||||
The program is free software, released under GPL. If you like this program and can make use of it, consider sponsoring or donating to help fund the project.
|
||||
There are currently 3 options for sponsoring:
|
||||
There are currently 4 options for sponsoring:
|
||||
|
||||
1. [GitHub Sponsors](https://github.com/sponsors/jonaski)
|
||||
2. [Patreon](https://www.patreon.com/jonaskvinge)
|
||||
3. [PayPal](https://paypal.me/jonaskvinge)
|
||||
1. [Patreon](https://www.patreon.com/jonaskvinge)
|
||||
2. [GitHub](https://github.com/sponsors/jonaski)
|
||||
3. [Ko-fi](https://ko-fi.com/jonaskvinge)
|
||||
4. [PayPal](https://paypal.me/jonaskvinge)
|
||||
|
||||
Funding developers is a way to contribute to open source projects you appreciate, it helps developers get the resources they need, and recognize contributors working behind the scenes to make open source better for everyone.
|
||||
|
||||
### :heavy_check_mark: Features:
|
||||
### :heavy_check_mark: Features
|
||||
|
||||
* Play and organize music
|
||||
* Supports WAV, FLAC, WavPack, Ogg FLAC, Ogg Vorbis, Ogg Opus, Ogg Speex, MPC, TrueAudio, AIFF, MP4, MP3, ASF and Monkey's Audio.
|
||||
@@ -45,39 +49,39 @@ Funding developers is a way to contribute to open source projects you appreciate
|
||||
* Playlist management
|
||||
* Smart and dynamic playlists
|
||||
* Advanced audio output and device configuration for bit-perfect playback on Linux
|
||||
* In-player song loudness analysis and song playback loudness normalization, as per EBU R 128
|
||||
* Edit tags on audio files
|
||||
* Fetch tags from MusicBrainz
|
||||
* Album cover art from [Last.fm](https://www.last.fm/), [Musicbrainz](https://musicbrainz.org/), [Discogs](https://www.discogs.com/), [Musixmatch](https://www.musixmatch.com/), [Deezer](https://www.deezer.com/), [Tidal](https://www.tidal.com/), [Qobuz](https://www.qobuz.com/) and [Spotify](https://www.spotify.com/)
|
||||
* Song lyrics from [AudD](https://audd.io/), [Genius](https://genius.com/), [Musixmatch](https://www.musixmatch.com/), [ChartLyrics](http://www.chartlyrics.com/), [lyrics.ovh](https://lyrics.ovh/) and [lololyrics.com](https://www.lololyrics.com/)
|
||||
* Song lyrics from [Genius](https://genius.com/), [Musixmatch](https://www.musixmatch.com/), [ChartLyrics](http://www.chartlyrics.com/), [lyrics.ovh](https://lyrics.ovh/), [lololyrics.com](https://www.lololyrics.com/), [songlyrics.com](https://www.songlyrics.com/), [azlyrics.com](https://www.azlyrics.com/) and [elyrics.net](https://www.elyrics.net/)
|
||||
* Support for multiple backends
|
||||
* Audio analyzer
|
||||
* Audio equalizer
|
||||
* Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
|
||||
* Scrobbler with support for [Last.fm](https://www.last.fm/), [Libre.fm](https://libre.fm/) and [ListenBrainz](https://listenbrainz.org/)
|
||||
* Subsonic, Tidal and Qobuz streaming support
|
||||
* Subsonic, Tidal, Spotify and Qobuz streaming support
|
||||
|
||||
|
||||
It has so far been tested to work on Linux, OpenBSD, FreeBSD, macOS and Windows.
|
||||
|
||||
**There currently isn't any macOS developers actively working on this project, so we might not be able to help you with issues related to macOS.**
|
||||
**Access to macOS and Windows releases are currently restricted to sponsors, a 5 USD monthly sponsorship is required. You can sponsor strawberry through <a href="https://www.patreon.com/jonaskvinge">Patreon</a> for direct access to new releases. If you are sponsoring through GitHub, Ko-fi or PayPal, please e-mail support AT strawberrymusicplayer.org for access to downloads.**
|
||||
|
||||
### :heavy_exclamation_mark: Requirements
|
||||
|
||||
To build Strawberry from source you need the following installed on your system with the additional development packages/headers:
|
||||
|
||||
* [CMake](https://cmake.org/)
|
||||
* [GNU Make](https://www.gnu.org/software/make/)
|
||||
* [GCC](https://gcc.gnu.org/) or [clang](https://clang.llvm.org/) compiler
|
||||
* C/C++ compiler ([GCC](https://gcc.gnu.org/), [Clang](https://clang.llvm.org/) or [MSVC](https://visualstudio.microsoft.com/vs/features/cplusplus/))
|
||||
* [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) or [pkgconf](https://github.com/pkgconf/pkgconf)
|
||||
* [Boost](https://www.boost.org/)
|
||||
* [GLib](https://developer.gnome.org/glib/)
|
||||
* [Protobuf](https://developers.google.com/protocol-buffers/)
|
||||
* [Qt 5.8 or higher (or Qt 6) with components Core, Gui, Widgets, Concurrent, Network and Sql](https://www.qt.io/)
|
||||
* [SQLite 3.9 or newer with FTS5](https://www.sqlite.org)
|
||||
* [ALSA (Linux required)](https://www.alsa-project.org/)
|
||||
* [D-Bus (Linux required)](https://www.freedesktop.org/wiki/Software/dbus/)
|
||||
* [GStreamer](https://gstreamer.freedesktop.org/) or [VLC](https://www.videolan.org)
|
||||
* [GnuTLS](https://www.gnutls.org/)
|
||||
* [TagLib 1.11.1 or higher](https://www.taglib.org/) or [TagParser](https://github.com/Martchus/tagparser)
|
||||
* [Qt 6.4.0 or higher with components Core, Concurrent, Gui, Widgets, Network, Sql and D-Bus](https://www.qt.io/)
|
||||
* [SQLite 3.9 or newer](https://www.sqlite.org)
|
||||
* [ALSA (Required on Linux)](https://www.alsa-project.org/)
|
||||
* [GStreamer](https://gstreamer.freedesktop.org/)
|
||||
* [TagLib 1.12 or higher](https://www.taglib.org/)
|
||||
* [ICU](https://unicode-org.github.io/icu/)
|
||||
* [KDSingleApplication](https://github.com/KDAB/KDSingleApplication)
|
||||
|
||||
Optional dependencies:
|
||||
|
||||
@@ -87,29 +91,27 @@ Optional dependencies:
|
||||
* Audio CD: [libcdio](https://www.gnu.org/software/libcdio/)
|
||||
* MTP devices: [libmtp](http://libmtp.sourceforge.net/)
|
||||
* iPod Classic devices: [libgpod](http://www.gtkpod.org/libgpod/)
|
||||
* EBU R 128 loudness normalization [libebur128](https://github.com/jiixyj/libebur128)
|
||||
|
||||
Either GStreamer or VLC engine is required, but only GStreamer is fully implemented, and works best, it is therefore recommended to use GStreamer.
|
||||
You should also install the gstreamer plugins base and good, and optionally bad, ugly and libav.
|
||||
You should also install the gstreamer plugins base and good, and optionally bad, ugly and libav to support all audio formats.
|
||||
|
||||
### :wrench: Compiling from source
|
||||
### :wrench: Compiling from source
|
||||
|
||||
### Get the code:
|
||||
|
||||
git clone https://github.com/strawberrymusicplayer/strawberry
|
||||
git clone --recursive https://github.com/strawberrymusicplayer/strawberry
|
||||
|
||||
### Compile and install:
|
||||
|
||||
cd strawberry
|
||||
mkdir build && cd build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j$(nproc)
|
||||
make -j $(nproc)
|
||||
sudo make install
|
||||
|
||||
To compile with Qt 6 use:
|
||||
|
||||
cmake .. -DBUILD_WITH_QT6=ON
|
||||
To compile on Windows with Visual Studio 2019 or 2022, see https://github.com/strawberrymusicplayer/strawberry-msvc
|
||||
|
||||
### :penguin: Packaging status
|
||||
|
||||
[](https://repology.org/metapackage/strawberry/versions)
|
||||
### :penguin: Packaging status
|
||||
|
||||
[](https://repology.org/metapackage/strawberry/versions)
|
||||
|
||||
@@ -2,18 +2,5 @@ find_program(LSB_RELEASE_EXEC lsb_release)
|
||||
find_program(DPKG_BUILDPACKAGE dpkg-buildpackage)
|
||||
|
||||
if (LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
|
||||
execute_process(COMMAND env LC_ALL=C date "+%a, %-d %b %Y %H:%M:%S %z" OUTPUT_VARIABLE DEB_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -cs"
|
||||
OUTPUT_VARIABLE DEB_CODENAME
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
if (DEB_CODENAME AND DEB_DATE)
|
||||
add_custom_target(deb
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
COMMAND ${DPKG_BUILDPACKAGE} -b -d -uc -us
|
||||
)
|
||||
endif()
|
||||
|
||||
add_custom_target(deb WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${DPKG_BUILDPACKAGE} -b -d -uc -us)
|
||||
endif()
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
#find_program(MACDEPLOYQT_EXECUTABLE NAMES macdeployqt PATHS /usr/local/opt/qt6/bin /usr/local/opt/qt5/bin /usr/local/bin REQUIRED)
|
||||
set(MACDEPLOYQT_EXECUTABLE "${CMAKE_BINARY_DIR}/3rdparty/macdeployqt/macdeployqt")
|
||||
find_program(MACDEPLOYQT_EXECUTABLE NAMES macdeployqt PATHS /usr/bin /usr/local/bin /opt/local/bin /usr/local/opt/qt6/bin REQUIRED)
|
||||
if(MACDEPLOYQT_EXECUTABLE)
|
||||
message(STATUS "Found macdeployqt: ${MACDEPLOYQT_EXECUTABLE}")
|
||||
else()
|
||||
message(WARNING "Missing macdeployqt executable.")
|
||||
endif()
|
||||
|
||||
find_program(MACDEPLOYCHECK_EXECUTABLE NAMES macdeploycheck PATHS /usr/bin /usr/local/bin /opt/local/bin /usr/local/opt/qt6/bin REQUIRED)
|
||||
if(MACDEPLOYCHECK_EXECUTABLE)
|
||||
message(STATUS "Found macdeploycheck: ${MACDEPLOYCHECK_EXECUTABLE}")
|
||||
else()
|
||||
message(WARNING "Missing macdeploycheck executable.")
|
||||
endif()
|
||||
|
||||
find_program(CREATEDMG_EXECUTABLE NAMES create-dmg REQUIRED)
|
||||
if(CREATEDMG_EXECUTABLE)
|
||||
message(STATUS "Found create-dmg: ${CREATEDMG_EXECUTABLE}")
|
||||
@@ -14,29 +20,33 @@ else()
|
||||
endif()
|
||||
|
||||
if(MACDEPLOYQT_EXECUTABLE)
|
||||
add_custom_target(copy_gstreamer_plugins
|
||||
#COMMAND ${CMAKE_SOURCE_DIR}/dist/macos/macgstcopy.sh strawberry.app
|
||||
)
|
||||
|
||||
if(APPLE_DEVELOPER_ID)
|
||||
set(MACDEPLOYQT_CODESIGN -codesign=${APPLE_DEVELOPER_ID})
|
||||
set(CREATEDMG_CODESIGN --codesign ${APPLE_DEVELOPER_ID})
|
||||
endif()
|
||||
if(CREATEDMG_SKIP_JENKINS)
|
||||
set(CREATEDMG_SKIP_JENKINS_ARG "--skip-jenkins")
|
||||
endif()
|
||||
|
||||
add_custom_target(deploy
|
||||
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/strawberry.app/Contents/{Frameworks,Resources}
|
||||
COMMAND cp -v ${CMAKE_SOURCE_DIR}/dist/macos/Info.plist ${CMAKE_BINARY_DIR}/strawberry.app/Contents/
|
||||
COMMAND cp -v ${CMAKE_SOURCE_DIR}/dist/macos/strawberry.icns ${CMAKE_BINARY_DIR}/strawberry.app/Contents/Resources/
|
||||
COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -verbose=3
|
||||
-executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/strawberry-tagreader
|
||||
-executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/gio-modules/libgiognutls.so
|
||||
#-executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/gst-plugin-scanner
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/dist/macos/macgstcopy.sh ${CMAKE_BINARY_DIR}/strawberry.app
|
||||
COMMAND ${MACDEPLOYQT_EXECUTABLE} strawberry.app -verbose=3 -executable=${CMAKE_BINARY_DIR}/strawberry.app/Contents/PlugIns/gst-plugin-scanner ${MACDEPLOYQT_CODESIGN}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
DEPENDS strawberry strawberry-tagreader copy_gstreamer_plugins macdeployqt
|
||||
)
|
||||
add_custom_target(deploycheck
|
||||
COMMAND ${CMAKE_BINARY_DIR}/ext/macdeploycheck/macdeploycheck strawberry.app
|
||||
DEPENDS macdeploycheck
|
||||
DEPENDS strawberry
|
||||
)
|
||||
if(MACDEPLOYCHECK_EXECUTABLE)
|
||||
add_custom_target(deploycheck
|
||||
COMMAND ${MACDEPLOYCHECK_EXECUTABLE} strawberry.app
|
||||
)
|
||||
endif()
|
||||
if(CREATEDMG_EXECUTABLE)
|
||||
add_custom_target(dmg
|
||||
COMMAND ${CREATEDMG_EXECUTABLE} --volname strawberry --background "${CMAKE_SOURCE_DIR}/dist/macos/dmg_background.png" --app-drop-link 450 218 --icon strawberry.app 150 218 --window-size 600 450 strawberry-${STRAWBERRY_VERSION_PACKAGE}-${CMAKE_HOST_SYSTEM_PROCESSOR}.dmg strawberry.app
|
||||
COMMAND ${CREATEDMG_EXECUTABLE} --volname strawberry --background "${CMAKE_SOURCE_DIR}/dist/macos/dmg_background.png" --app-drop-link 450 218 --icon strawberry.app 150 218 --window-size 600 450 ${CREATEDMG_CODESIGN} ${CREATEDMG_SKIP_JENKINS_ARG} strawberry-${STRAWBERRY_VERSION_PACKAGE}-${CMAKE_HOST_SYSTEM_PROCESSOR}.dmg strawberry.app
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
DEPENDS deploy deploycheck
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
# - Try to find the libcppunit libraries
|
||||
# Once done this will define
|
||||
#
|
||||
# CppUnit_FOUND - system has libcppunit
|
||||
# CPPUNIT_INCLUDE_DIR - the libcppunit include directory
|
||||
# CPPUNIT_LIBRARIES - libcppunit library
|
||||
|
||||
#include (MacroEnsureVersion)
|
||||
|
||||
if(NOT CPPUNIT_MIN_VERSION)
|
||||
SET(CPPUNIT_MIN_VERSION 1.12.0)
|
||||
endif(NOT CPPUNIT_MIN_VERSION)
|
||||
|
||||
FIND_PROGRAM(CPPUNIT_CONFIG_EXECUTABLE cppunit-config )
|
||||
|
||||
IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
|
||||
|
||||
# in cache already
|
||||
SET(CppUnit_FOUND TRUE)
|
||||
|
||||
ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
|
||||
|
||||
SET(CPPUNIT_INCLUDE_DIR)
|
||||
SET(CPPUNIT_LIBRARIES)
|
||||
|
||||
IF(CPPUNIT_CONFIG_EXECUTABLE)
|
||||
EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --cflags RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_CFLAGS)
|
||||
EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --libs RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_LIBRARIES)
|
||||
EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_INSTALLED_VERSION)
|
||||
STRING(REGEX REPLACE "-I(.+)" "\\1" CPPUNIT_CFLAGS "${CPPUNIT_CFLAGS}")
|
||||
ELSE(CPPUNIT_CONFIG_EXECUTABLE)
|
||||
# in case win32 needs to find it the old way?
|
||||
FIND_PATH(CPPUNIT_CFLAGS cppunit/TestRunner.h PATHS /usr/include /usr/local/include )
|
||||
FIND_LIBRARY(CPPUNIT_LIBRARIES NAMES cppunit PATHS /usr/lib /usr/local/lib )
|
||||
# how can we find cppunit version?
|
||||
MESSAGE (STATUS "Ensure you cppunit installed version is at least ${CPPUNIT_MIN_VERSION}")
|
||||
SET (CPPUNIT_INSTALLED_VERSION ${CPPUNIT_MIN_VERSION})
|
||||
ENDIF(CPPUNIT_CONFIG_EXECUTABLE)
|
||||
|
||||
SET(CPPUNIT_INCLUDE_DIR ${CPPUNIT_CFLAGS} "${CPPUNIT_CFLAGS}/cppunit")
|
||||
|
||||
ENDIF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
|
||||
|
||||
IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
|
||||
|
||||
SET(CppUnit_FOUND TRUE)
|
||||
|
||||
if(NOT CppUnit_FIND_QUIETLY)
|
||||
MESSAGE (STATUS "Found cppunit: ${CPPUNIT_LIBRARIES}")
|
||||
endif(NOT CppUnit_FIND_QUIETLY)
|
||||
|
||||
IF(CPPUNIT_CONFIG_EXECUTABLE)
|
||||
EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_INSTALLED_VERSION)
|
||||
ENDIF(CPPUNIT_CONFIG_EXECUTABLE)
|
||||
|
||||
#macro_ensure_version( ${CPPUNIT_MIN_VERSION} ${CPPUNIT_INSTALLED_VERSION} CPPUNIT_INSTALLED_VERSION_OK )
|
||||
|
||||
#IF(NOT CPPUNIT_INSTALLED_VERSION_OK)
|
||||
# MESSAGE ("** CppUnit version is too old: found ${CPPUNIT_INSTALLED_VERSION} installed, ${CPPUNIT_MIN_VERSION} or major is required")
|
||||
# SET(CppUnit_FOUND FALSE)
|
||||
#ENDIF(NOT CPPUNIT_INSTALLED_VERSION_OK)
|
||||
|
||||
ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
|
||||
|
||||
SET(CppUnit_FOUND FALSE CACHE BOOL "Not found cppunit library")
|
||||
|
||||
ENDIF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
|
||||
|
||||
MARK_AS_ADVANCED(CPPUNIT_INCLUDE_DIR CPPUNIT_LIBRARIES)
|
||||
@@ -1,132 +0,0 @@
|
||||
#
|
||||
# Try to find FFTW3 library
|
||||
# (see www.fftw.org)
|
||||
# Once run this will define:
|
||||
#
|
||||
# FFTW3_FOUND
|
||||
# FFTW3_INCLUDE_DIR
|
||||
# FFTW3_LIBRARIES
|
||||
# FFTW3_LINK_DIRECTORIES
|
||||
#
|
||||
# You may set one of these options before including this file:
|
||||
# FFTW3_USE_SSE2
|
||||
#
|
||||
# TODO: _F_ versions.
|
||||
#
|
||||
# Jan Woetzel 05/2004
|
||||
# www.mip.informatik.uni-kiel.de
|
||||
# --------------------------------
|
||||
|
||||
FIND_PATH(FFTW3_INCLUDE_DIR fftw3.h
|
||||
${FFTW3_DIR}/include
|
||||
${FFTW3_HOME}/include
|
||||
${FFTW3_DIR}
|
||||
${FFTW3_HOME}
|
||||
$ENV{FFTW3_DIR}/include
|
||||
$ENV{FFTW3_HOME}/include
|
||||
$ENV{FFTW3_DIR}
|
||||
$ENV{FFTW3_HOME}
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
$ENV{SOURCE_DIR}/fftw3
|
||||
$ENV{SOURCE_DIR}/fftw3/include
|
||||
$ENV{SOURCE_DIR}/fftw
|
||||
$ENV{SOURCE_DIR}/fftw/include
|
||||
)
|
||||
#MESSAGE("DBG FFTW3_INCLUDE_DIR=${FFTW3_INCLUDE_DIR}")
|
||||
|
||||
|
||||
SET(FFTW3_POSSIBLE_LIBRARY_PATH
|
||||
${FFTW3_DIR}/lib
|
||||
${FFTW3_HOME}/lib
|
||||
${FFTW3_DIR}
|
||||
${FFTW3_HOME}
|
||||
$ENV{FFTW3_DIR}/lib
|
||||
$ENV{FFTW3_HOME}/lib
|
||||
$ENV{FFTW3_DIR}
|
||||
$ENV{FFTW3_HOME}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
$ENV{SOURCE_DIR}/fftw3
|
||||
$ENV{SOURCE_DIR}/fftw3/lib
|
||||
$ENV{SOURCE_DIR}/fftw
|
||||
$ENV{SOURCE_DIR}/fftw/lib
|
||||
)
|
||||
|
||||
|
||||
# The lib prefix is contained in filename of W32, unfortunately. In the "general" lib:
|
||||
FIND_LIBRARY(FFTW3_FFTW_LIBRARY
|
||||
NAMES fftw3 libfftw libfftw3 libfftw3-3
|
||||
PATHS
|
||||
${FFTW3_POSSIBLE_LIBRARY_PATH}
|
||||
)
|
||||
#MESSAGE("DBG FFTW3_FFTW_LIBRARY=${FFTW3_FFTW_LIBRARY}")
|
||||
|
||||
FIND_LIBRARY(FFTW3_FFTWF_LIBRARY
|
||||
NAMES fftwf3 fftw3f fftwf libfftwf libfftwf3 libfftw3f-3
|
||||
PATHS
|
||||
${FFTW3_POSSIBLE_LIBRARY_PATH}
|
||||
)
|
||||
#MESSAGE("DBG FFTW3_FFTWF_LIBRARY=${FFTW3_FFTWF_LIBRARY}")
|
||||
|
||||
FIND_LIBRARY(FFTW3_FFTWL_LIBRARY
|
||||
NAMES fftwl3 fftw3l fftwl libfftwl libfftwl3 libfftw3l-3
|
||||
PATHS
|
||||
${FFTW3_POSSIBLE_LIBRARY_PATH}
|
||||
)
|
||||
#MESSAGE("DBG FFTW3_FFTWF_LIBRARY=${FFTW3_FFTWL_LIBRARY}")
|
||||
|
||||
|
||||
FIND_LIBRARY(FFTW3_FFTW_SSE2_LIBRARY
|
||||
NAMES fftw_sse2 fftw3_sse2 libfftw_sse2 libfftw3_sse2
|
||||
PATHS
|
||||
${FFTW3_POSSIBLE_LIBRARY_PATH}
|
||||
)
|
||||
#MESSAGE("DBG FFTW3_FFTW_SSE2_LIBRARY=${FFTW3_FFTW_SSE2_LIBRARY}")
|
||||
|
||||
FIND_LIBRARY(FFTW3_FFTWF_SSE_LIBRARY
|
||||
NAMES fftwf_sse fftwf3_sse libfftwf_sse libfftwf3_sse
|
||||
PATHS
|
||||
${FFTW3_POSSIBLE_LIBRARY_PATH}
|
||||
)
|
||||
#MESSAGE("DBG FFTW3_FFTWF_SSE_LIBRARY=${FFTW3_FFTWF_SSE_LIBRARY}")
|
||||
|
||||
|
||||
# --------------------------------
|
||||
# select one of the above
|
||||
# default:
|
||||
IF (FFTW3_FFTW_LIBRARY)
|
||||
SET(FFTW3_LIBRARIES ${FFTW3_FFTW_LIBRARY})
|
||||
ENDIF (FFTW3_FFTW_LIBRARY)
|
||||
# specialized:
|
||||
IF (FFTW3_USE_SSE2 AND FFTW3_FFTW_SSE2_LIBRARY)
|
||||
SET(FFTW3_LIBRARIES ${FFTW3_FFTW_SSE2_LIBRARY})
|
||||
ENDIF (FFTW3_USE_SSE2 AND FFTW3_FFTW_SSE2_LIBRARY)
|
||||
|
||||
# --------------------------------
|
||||
|
||||
IF(FFTW3_LIBRARIES)
|
||||
IF (FFTW3_INCLUDE_DIR)
|
||||
|
||||
# OK, found all we need
|
||||
SET(FFTW3_FOUND TRUE)
|
||||
GET_FILENAME_COMPONENT(FFTW3_LINK_DIRECTORIES ${FFTW3_LIBRARIES} PATH)
|
||||
|
||||
ELSE (FFTW3_INCLUDE_DIR)
|
||||
MESSAGE("FFTW3 include dir not found. Set FFTW3_DIR to find it.")
|
||||
ENDIF(FFTW3_INCLUDE_DIR)
|
||||
ELSE(FFTW3_LIBRARIES)
|
||||
MESSAGE("FFTW3 lib not found. Set FFTW3_DIR to find it.")
|
||||
ENDIF(FFTW3_LIBRARIES)
|
||||
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
FFTW3_INCLUDE_DIR
|
||||
FFTW3_LIBRARIES
|
||||
FFTW3_FFTW_LIBRARY
|
||||
FFTW3_FFTW_SSE2_LIBRARY
|
||||
FFTW3_FFTWF_LIBRARY
|
||||
FFTW3_FFTWF_SSE_LIBRARY
|
||||
FFTW3_FFTWL_LIBRARY
|
||||
FFTW3_LINK_DIRECTORIES
|
||||
)
|
||||
@@ -12,10 +12,17 @@ if (LSB_RELEASE_EXEC AND RPMBUILD_EXEC)
|
||||
OUTPUT_VARIABLE DIST_RELEASE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | sed 's/\\.//g' | cut -d' ' -f3"
|
||||
OUTPUT_VARIABLE DIST_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if (${DIST_NAME} STREQUAL "openmandrivalinux")
|
||||
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | sed 's/\\./0/g' | cut -d' ' -f3"
|
||||
OUTPUT_VARIABLE DIST_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
else()
|
||||
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -ds | tr '[:upper:]' '[:lower:]' | sed 's/\"//g' | sed 's/\\.//g' | cut -d' ' -f3"
|
||||
OUTPUT_VARIABLE DIST_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
endif()
|
||||
if (DIST_NAME)
|
||||
|
||||
message(STATUS "Distro Name: ${DIST_NAME}")
|
||||
@@ -44,6 +51,8 @@ if (LSB_RELEASE_EXEC AND RPMBUILD_EXEC)
|
||||
set(RPM_DISTRO "el${DIST_VERSION}")
|
||||
elseif (${DIST_NAME} STREQUAL "mageia" AND DIST_RELEASE)
|
||||
set(RPM_DISTRO "mga${DIST_RELEASE}")
|
||||
elseif (${DIST_NAME} STREQUAL "openmandrivalinux" AND DIST_VERSION)
|
||||
set(RPM_DISTRO "omv${DIST_VERSION}")
|
||||
endif()
|
||||
|
||||
if(NOT RPM_DISTRO)
|
||||
|
||||
@@ -24,7 +24,7 @@ macro(summary_show)
|
||||
list(SORT summary_willbuild)
|
||||
list(SORT summary_willnotbuild)
|
||||
message("")
|
||||
message("Building strawberry version: ${STRAWBERRY_VERSION_DISPLAY}")
|
||||
message("Building strawberry version: ${STRAWBERRY_VERSION_DISPLAY}, Qt version ${Qt${QT_VERSION_MAJOR}Core_VERSION}")
|
||||
summary_show_part(summary_willbuild "The following components will be built:")
|
||||
summary_show_part(summary_willnotbuild "The following components WILL NOT be built:")
|
||||
message("")
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
find_program(GETTEXT_XGETTEXT_EXECUTABLE xgettext)
|
||||
if(NOT GETTEXT_XGETTEXT_EXECUTABLE)
|
||||
message(FATAL_ERROR "Could not find xgettext executable")
|
||||
endif(NOT GETTEXT_XGETTEXT_EXECUTABLE)
|
||||
|
||||
set (XGETTEXT_OPTIONS
|
||||
--qt
|
||||
--keyword=tr:1,2c
|
||||
--keyword=tr --flag=tr:1:pass-c-format --flag=tr:1:pass-qt-format
|
||||
--keyword=trUtf8 --flag=tr:1:pass-c-format --flag=tr:1:pass-qt-format
|
||||
--keyword=translate:2,3c
|
||||
--keyword=translate:2 --flag=translate:2:pass-c-format --flag=translate:2:pass-qt-format
|
||||
--keyword=QT_TR_NOOP --flag=QT_TR_NOOP:1:pass-c-format --flag=QT_TR_NOOP:1:pass-qt-format
|
||||
--keyword=QT_TRANSLATE_NOOP:2 --flag=QT_TRANSLATE_NOOP:2:pass-c-format --flag=QT_TRANSLATE_NOOP:2:pass-qt-format
|
||||
--keyword=_ --flag=_:1:pass-c-format --flag=_:1:pass-qt-format
|
||||
--keyword=N_ --flag=N_:1:pass-c-format --flag=N_:1:pass-qt-format
|
||||
--from-code=utf-8
|
||||
)
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/translations)
|
||||
|
||||
macro(add_pot outfiles header pot)
|
||||
# Make relative filenames for all source files
|
||||
set(add_pot_sources)
|
||||
foreach(_filename ${ARGN})
|
||||
get_filename_component(_absolute_filename ${_filename} ABSOLUTE)
|
||||
file(RELATIVE_PATH _relative_filename ${CMAKE_CURRENT_SOURCE_DIR} ${_absolute_filename})
|
||||
list(APPEND add_pot_sources ${_relative_filename})
|
||||
endforeach(_filename)
|
||||
|
||||
# Generate the .pot
|
||||
add_custom_command(
|
||||
OUTPUT ${pot}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMAND ${GETTEXT_XGETTEXT_EXECUTABLE} ${XGETTEXT_OPTIONS} -s -C --omit-header --output=${CMAKE_CURRENT_BINARY_DIR}/pot.temp ${add_pot_sources}
|
||||
COMMAND cat ${header} ${CMAKE_CURRENT_BINARY_DIR}/pot.temp > ${pot}
|
||||
DEPENDS ${add_pot_sources} ${header}
|
||||
)
|
||||
|
||||
list(APPEND ${outfiles} ${pot})
|
||||
endmacro(add_pot)
|
||||
|
||||
# Syntax is:
|
||||
# add_po(sources_var po_prefix LANGUAGES language1 language2 ... DIRECTORY dir)
|
||||
|
||||
macro(add_po outfiles po_prefix)
|
||||
parse_arguments(ADD_PO
|
||||
"LANGUAGES;DIRECTORY"
|
||||
""
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
foreach (_lang ${ADD_PO_LANGUAGES})
|
||||
set(_po_filename "${_lang}.po")
|
||||
set(_po_filepath "${CMAKE_CURRENT_SOURCE_DIR}/${ADD_PO_DIRECTORY}/${_po_filename}")
|
||||
set(_qm_filename "strawberry_${_lang}.qm")
|
||||
set(_qm_filepath "${CMAKE_CURRENT_BINARY_DIR}/${ADD_PO_DIRECTORY}/${_qm_filename}")
|
||||
|
||||
# Convert the .po files to .qm files
|
||||
add_custom_command(
|
||||
OUTPUT ${_qm_filepath}
|
||||
COMMAND ${QT_LCONVERT_EXECUTABLE} ARGS ${_po_filepath} -o ${_qm_filepath} -of qm
|
||||
DEPENDS ${_po_filepath} ${_po_filepath}
|
||||
)
|
||||
|
||||
list(APPEND ${outfiles} ${_qm_filepath})
|
||||
list(APPEND INSTALL_TRANSLATIONS_FILES ${_qm_filepath})
|
||||
endforeach (_lang)
|
||||
|
||||
# Generate a qrc file for the translations
|
||||
if(NOT INSTALL_TRANSLATIONS)
|
||||
set(_qrc ${CMAKE_CURRENT_BINARY_DIR}/${ADD_PO_DIRECTORY}/translations.qrc)
|
||||
file(WRITE ${_qrc} "<RCC><qresource prefix=\"/${ADD_PO_DIRECTORY}\">")
|
||||
foreach(_lang ${ADD_PO_LANGUAGES})
|
||||
file(APPEND ${_qrc} "<file>${po_prefix}${_lang}.qm</file>")
|
||||
endforeach(_lang)
|
||||
file(APPEND ${_qrc} "</qresource></RCC>")
|
||||
qt_add_resources(${outfiles} ${_qrc})
|
||||
endif()
|
||||
endmacro(add_po)
|
||||
@@ -1,35 +1,19 @@
|
||||
set(STRAWBERRY_VERSION_MAJOR 1)
|
||||
set(STRAWBERRY_VERSION_MINOR 0)
|
||||
set(STRAWBERRY_VERSION_PATCH 0)
|
||||
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
||||
set(STRAWBERRY_VERSION_MINOR 2)
|
||||
set(STRAWBERRY_VERSION_PATCH 1)
|
||||
set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
||||
|
||||
set(INCLUDE_GIT_REVISION OFF)
|
||||
|
||||
set(majorminorpatch "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}.${STRAWBERRY_VERSION_PATCH}")
|
||||
|
||||
set(STRAWBERRY_VERSION_DISPLAY "${majorminorpatch}")
|
||||
set(STRAWBERRY_VERSION_PACKAGE "${majorminorpatch}")
|
||||
set(STRAWBERRY_VERSION_RPM_V "${majorminorpatch}")
|
||||
set(STRAWBERRY_VERSION_RPM_R "1")
|
||||
set(STRAWBERRY_VERSION_PAC_V "${majorminorpatch}")
|
||||
set(STRAWBERRY_VERSION_PAC_R "1")
|
||||
|
||||
if(${STRAWBERRY_VERSION_PATCH} EQUAL "0")
|
||||
set(STRAWBERRY_VERSION_DISPLAY "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}")
|
||||
endif(${STRAWBERRY_VERSION_PATCH} EQUAL "0")
|
||||
|
||||
if(STRAWBERRY_VERSION_PRERELEASE)
|
||||
set(STRAWBERRY_VERSION_DISPLAY "${STRAWBERRY_VERSION_DISPLAY} ${STRAWBERRY_VERSION_PRERELEASE}")
|
||||
set(STRAWBERRY_VERSION_RPM_R "0.${STRAWBERRY_VERSION_PRERELEASE}")
|
||||
set(STRAWBERRY_VERSION_PACKAGE "${STRAWBERRY_VERSION_PACKAGE}${STRAWBERRY_VERSION_PRERELEASE}")
|
||||
endif(STRAWBERRY_VERSION_PRERELEASE)
|
||||
|
||||
|
||||
if(INCLUDE_GIT_REVISION AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
if(FORCE_GIT_REVISION)
|
||||
set(GIT_REVISION ${FORCE_GIT_REVISION})
|
||||
elseif(INCLUDE_GIT_REVISION AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
|
||||
find_program(GIT_EXECUTABLE git)
|
||||
if(NOT GIT_EXECUTABLE OR GIT_EXECUTABLE-NOTFOUND)
|
||||
message(FATAL_ERROR "Missing GIT executable." )
|
||||
message(FATAL_ERROR "Missing Git executable." )
|
||||
endif()
|
||||
|
||||
# Get the current working branch
|
||||
@@ -52,15 +36,11 @@ if(INCLUDE_GIT_REVISION AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
)
|
||||
|
||||
if(NOT ${GIT_CMD_RESULT_REVISION} EQUAL 0)
|
||||
message(FATAL_ERROR "GIT command failed to get revision string '${GIT_REVISION}'")
|
||||
message(FATAL_ERROR "Git command failed to get revision string '${GIT_REVISION}'")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
if(FORCE_GIT_REVISION)
|
||||
set(GIT_REVISION ${FORCE_GIT_REVISION})
|
||||
endif()
|
||||
|
||||
if(GIT_REVISION)
|
||||
|
||||
string(REGEX REPLACE "^(.+)-([0-9]+)-(g[a-f0-9]+)$" "\\1;\\2;\\3" GIT_PARTS ${GIT_REVISION})
|
||||
@@ -71,7 +51,7 @@ if(GIT_REVISION)
|
||||
|
||||
list(LENGTH GIT_PARTS GIT_PARTS_LENGTH)
|
||||
if(NOT GIT_PARTS_LENGTH EQUAL 3)
|
||||
message(FATAL_ERROR "Failed to parse git revision string '${GIT_REVISION}'")
|
||||
set(GIT_PARTS "${majorminorpatch};0;${GIT_REVISION}")
|
||||
endif()
|
||||
|
||||
list(GET GIT_PARTS 0 GIT_TAGNAME)
|
||||
@@ -82,15 +62,23 @@ if(GIT_REVISION)
|
||||
|
||||
set(STRAWBERRY_VERSION_DISPLAY "${GIT_REVISION}")
|
||||
set(STRAWBERRY_VERSION_PACKAGE "${GIT_TAGNAME}.${GIT_COMMITCOUNT}.${GIT_SHA1}")
|
||||
set(STRAWBERRY_VERSION_RPM_V "${GIT_TAGNAME}")
|
||||
string(REPLACE "-" "~" STRAWBERRY_VERSION_RPM_V "${GIT_TAGNAME}")
|
||||
set(STRAWBERRY_VERSION_RPM_R "2.${GIT_COMMITCOUNT}.${GIT_SHA1}")
|
||||
set(STRAWBERRY_VERSION_PAC_V "${GIT_TAGNAME}.r${GIT_COMMITCOUNT}.${GIT_SHA1}")
|
||||
set(STRAWBERRY_VERSION_PAC_R "1")
|
||||
|
||||
else()
|
||||
if(STRAWBERRY_VERSION_PRERELEASE)
|
||||
set(STRAWBERRY_VERSION_DISPLAY "${majorminorpatch}-${STRAWBERRY_VERSION_PRERELEASE}")
|
||||
set(STRAWBERRY_VERSION_RPM_V "${majorminorpatch}~${STRAWBERRY_VERSION_PRERELEASE}")
|
||||
set(STRAWBERRY_VERSION_PACKAGE "${majorminorpatch}${STRAWBERRY_VERSION_PRERELEASE}")
|
||||
else()
|
||||
set(STRAWBERRY_VERSION_DISPLAY "${majorminorpatch}")
|
||||
set(STRAWBERRY_VERSION_PACKAGE "${majorminorpatch}")
|
||||
set(STRAWBERRY_VERSION_RPM_V "${majorminorpatch}")
|
||||
endif()
|
||||
set(STRAWBERRY_VERSION_RPM_R "1")
|
||||
endif()
|
||||
|
||||
message(STATUS "Strawberry Version:")
|
||||
message(STATUS "Display: ${STRAWBERRY_VERSION_DISPLAY}")
|
||||
message(STATUS "Package: ${STRAWBERRY_VERSION_PACKAGE}")
|
||||
message(STATUS "RPM: ${STRAWBERRY_VERSION_RPM_V}-${STRAWBERRY_VERSION_RPM_R}")
|
||||
message(STATUS "PAC: ${STRAWBERRY_VERSION_PAC_V}-${STRAWBERRY_VERSION_PAC_R}")
|
||||
|
||||
3
crowdin.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
files:
|
||||
- source: /src/translations/strawberry_en_US.ts
|
||||
translation: /src/translations/strawberry_%locale_with_underscore%.ts
|
||||
@@ -1,21 +1,17 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>schema/schema.sql</file>
|
||||
<file>schema/schema-1.sql</file>
|
||||
<file>schema/schema-2.sql</file>
|
||||
<file>schema/schema-3.sql</file>
|
||||
<file>schema/schema-4.sql</file>
|
||||
<file>schema/schema-5.sql</file>
|
||||
<file>schema/schema-6.sql</file>
|
||||
<file>schema/schema-7.sql</file>
|
||||
<file>schema/schema-8.sql</file>
|
||||
<file>schema/schema-9.sql</file>
|
||||
<file>schema/schema-10.sql</file>
|
||||
<file>schema/schema-11.sql</file>
|
||||
<file>schema/schema-12.sql</file>
|
||||
<file>schema/schema-13.sql</file>
|
||||
<file>schema/schema-14.sql</file>
|
||||
<file>schema/schema-15.sql</file>
|
||||
<file>schema/schema-16.sql</file>
|
||||
<file>schema/schema-17.sql</file>
|
||||
<file>schema/schema-18.sql</file>
|
||||
<file>schema/schema-19.sql</file>
|
||||
<file>schema/schema-20.sql</file>
|
||||
<file>schema/device-schema.sql</file>
|
||||
<file>style/strawberry.css</file>
|
||||
<file>style/smartplaylistsearchterm.css</file>
|
||||
@@ -46,8 +42,9 @@
|
||||
<file>pictures/rainbowdash.png</file>
|
||||
<file>pictures/star-on.png</file>
|
||||
<file>pictures/star-off.png</file>
|
||||
<file>fonts/HumongousofEternitySt.ttf</file>
|
||||
<file>mood/sample.mood</file>
|
||||
<file>text/ghosts.txt</file>
|
||||
<file>pictures/sidebar-background.png</file>
|
||||
<file>style/dynamicplaylistcontrols.css</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<file>icons/128x128/document-open-folder.png</file>
|
||||
<file>icons/128x128/document-open.png</file>
|
||||
<file>icons/128x128/document-save.png</file>
|
||||
<file>icons/128x128/document-save-all.png</file>
|
||||
<file>icons/128x128/document-search.png</file>
|
||||
<file>icons/128x128/download.png</file>
|
||||
<file>icons/128x128/edit-clear-list.png</file>
|
||||
@@ -90,11 +91,13 @@
|
||||
<file>icons/128x128/love.png</file>
|
||||
<file>icons/128x128/subsonic.png</file>
|
||||
<file>icons/128x128/tidal.png</file>
|
||||
<file>icons/128x128/spotify.png</file>
|
||||
<file>icons/128x128/qobuz.png</file>
|
||||
<file>icons/128x128/multimedia-player-ipod-standard-black.png</file>
|
||||
<file>icons/128x128/radio.png</file>
|
||||
<file>icons/128x128/somafm.png</file>
|
||||
<file>icons/128x128/radioparadise.png</file>
|
||||
<file>icons/128x128/musicbrainz.png</file>
|
||||
<file>icons/64x64/albums.png</file>
|
||||
<file>icons/64x64/alsa.png</file>
|
||||
<file>icons/64x64/application-exit.png</file>
|
||||
@@ -119,6 +122,7 @@
|
||||
<file>icons/64x64/document-open-folder.png</file>
|
||||
<file>icons/64x64/document-open.png</file>
|
||||
<file>icons/64x64/document-save.png</file>
|
||||
<file>icons/64x64/document-save-all.png</file>
|
||||
<file>icons/64x64/document-search.png</file>
|
||||
<file>icons/64x64/download.png</file>
|
||||
<file>icons/64x64/edit-clear-list.png</file>
|
||||
@@ -186,11 +190,13 @@
|
||||
<file>icons/64x64/love.png</file>
|
||||
<file>icons/64x64/subsonic.png</file>
|
||||
<file>icons/64x64/tidal.png</file>
|
||||
<file>icons/64x64/spotify.png</file>
|
||||
<file>icons/64x64/qobuz.png</file>
|
||||
<file>icons/64x64/multimedia-player-ipod-standard-black.png</file>
|
||||
<file>icons/64x64/radio.png</file>
|
||||
<file>icons/64x64/somafm.png</file>
|
||||
<file>icons/64x64/radioparadise.png</file>
|
||||
<file>icons/64x64/musicbrainz.png</file>
|
||||
<file>icons/48x48/albums.png</file>
|
||||
<file>icons/48x48/alsa.png</file>
|
||||
<file>icons/48x48/application-exit.png</file>
|
||||
@@ -216,6 +222,7 @@
|
||||
<file>icons/48x48/document-open-remote.png</file>
|
||||
<file>icons/48x48/document-open.png</file>
|
||||
<file>icons/48x48/document-save.png</file>
|
||||
<file>icons/48x48/document-save-all.png</file>
|
||||
<file>icons/48x48/document-search.png</file>
|
||||
<file>icons/48x48/download.png</file>
|
||||
<file>icons/48x48/edit-clear-list.png</file>
|
||||
@@ -285,12 +292,14 @@
|
||||
<file>icons/48x48/moodbar.png</file>
|
||||
<file>icons/48x48/love.png</file>
|
||||
<file>icons/48x48/subsonic.png</file>
|
||||
<file>icons/48x48/tidal.png</file>
|
||||
<file>icons/48x48/qobuz.png</file>
|
||||
<file>icons/48x48/tidal.png</file>
|
||||
<file>icons/48x48/spotify.png</file>
|
||||
<file>icons/48x48/qobuz.png</file>
|
||||
<file>icons/48x48/multimedia-player-ipod-standard-black.png</file>
|
||||
<file>icons/48x48/radio.png</file>
|
||||
<file>icons/48x48/somafm.png</file>
|
||||
<file>icons/48x48/radioparadise.png</file>
|
||||
<file>icons/48x48/musicbrainz.png</file>
|
||||
<file>icons/32x32/albums.png</file>
|
||||
<file>icons/32x32/alsa.png</file>
|
||||
<file>icons/32x32/application-exit.png</file>
|
||||
@@ -316,6 +325,7 @@
|
||||
<file>icons/32x32/document-open-remote.png</file>
|
||||
<file>icons/32x32/document-open.png</file>
|
||||
<file>icons/32x32/document-save.png</file>
|
||||
<file>icons/32x32/document-save-all.png</file>
|
||||
<file>icons/32x32/document-search.png</file>
|
||||
<file>icons/32x32/download.png</file>
|
||||
<file>icons/32x32/edit-clear-list.png</file>
|
||||
@@ -386,11 +396,13 @@
|
||||
<file>icons/32x32/love.png</file>
|
||||
<file>icons/32x32/subsonic.png</file>
|
||||
<file>icons/32x32/tidal.png</file>
|
||||
<file>icons/32x32/spotify.png</file>
|
||||
<file>icons/32x32/qobuz.png</file>
|
||||
<file>icons/32x32/multimedia-player-ipod-standard-black.png</file>
|
||||
<file>icons/32x32/radio.png</file>
|
||||
<file>icons/32x32/somafm.png</file>
|
||||
<file>icons/32x32/radioparadise.png</file>
|
||||
<file>icons/32x32/musicbrainz.png</file>
|
||||
<file>icons/22x22/albums.png</file>
|
||||
<file>icons/22x22/alsa.png</file>
|
||||
<file>icons/22x22/application-exit.png</file>
|
||||
@@ -416,6 +428,7 @@
|
||||
<file>icons/22x22/document-open-remote.png</file>
|
||||
<file>icons/22x22/document-open.png</file>
|
||||
<file>icons/22x22/document-save.png</file>
|
||||
<file>icons/22x22/document-save-all.png</file>
|
||||
<file>icons/22x22/document-search.png</file>
|
||||
<file>icons/22x22/download.png</file>
|
||||
<file>icons/22x22/edit-clear-list.png</file>
|
||||
@@ -486,10 +499,12 @@
|
||||
<file>icons/22x22/love.png</file>
|
||||
<file>icons/22x22/subsonic.png</file>
|
||||
<file>icons/22x22/tidal.png</file>
|
||||
<file>icons/22x22/spotify.png</file>
|
||||
<file>icons/22x22/qobuz.png</file>
|
||||
<file>icons/22x22/multimedia-player-ipod-standard-black.png</file>
|
||||
<file>icons/22x22/radio.png</file>
|
||||
<file>icons/22x22/somafm.png</file>
|
||||
<file>icons/22x22/radioparadise.png</file>
|
||||
<file>icons/22x22/musicbrainz.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
BIN
data/icons/128x128/document-save-all.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
data/icons/128x128/musicbrainz.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
data/icons/128x128/spotify.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
data/icons/22x22/document-save-all.png
Normal file
|
After Width: | Height: | Size: 921 B |
BIN
data/icons/22x22/musicbrainz.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
data/icons/22x22/spotify.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
data/icons/32x32/document-save-all.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
data/icons/32x32/musicbrainz.png
Normal file
|
After Width: | Height: | Size: 947 B |
BIN
data/icons/32x32/spotify.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
data/icons/48x48/document-save-all.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
data/icons/48x48/musicbrainz.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
data/icons/48x48/spotify.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
data/icons/64x64/document-save-all.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
data/icons/64x64/musicbrainz.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
data/icons/64x64/spotify.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
data/icons/full/document-save-all.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
data/icons/full/musicbrainz.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
data/icons/full/spotify.png
Executable file
|
After Width: | Height: | Size: 16 KiB |
BIN
data/pictures/sidebar-background.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
@@ -1,35 +1,35 @@
|
||||
CREATE TABLE device_%deviceid_directories (
|
||||
path TEXT NOT NULL DEFAULT '',
|
||||
path TEXT NOT NULL,
|
||||
subdirs INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE device_%deviceid_subdirectories (
|
||||
directory_id INTEGER NOT NULL,
|
||||
path TEXT NOT NULL DEFAULT '',
|
||||
path TEXT NOT NULL,
|
||||
mtime INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE device_%deviceid_songs (
|
||||
|
||||
title TEXT DEFAULT '',
|
||||
album TEXT DEFAULT '',
|
||||
artist TEXT DEFAULT '',
|
||||
albumartist TEXT DEFAULT '',
|
||||
title TEXT,
|
||||
album TEXT,
|
||||
artist TEXT,
|
||||
albumartist TEXT,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT DEFAULT '',
|
||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||
genre TEXT,
|
||||
compilation INTEGER NOT NULL DEFAULT 0,
|
||||
composer TEXT DEFAULT '',
|
||||
performer TEXT DEFAULT '',
|
||||
grouping TEXT DEFAULT '',
|
||||
comment TEXT DEFAULT '',
|
||||
lyrics TEXT DEFAULT '',
|
||||
composer TEXT,
|
||||
performer TEXT,
|
||||
grouping TEXT,
|
||||
comment TEXT,
|
||||
lyrics TEXT,
|
||||
|
||||
artist_id TEXT DEFAULT '',
|
||||
album_id TEXT DEFAULT '',
|
||||
song_id TEXT DEFAULT '',
|
||||
artist_id TEXT,
|
||||
album_id TEXT,
|
||||
song_id TEXT,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
@@ -40,14 +40,14 @@ CREATE TABLE device_%deviceid_songs (
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||
url TEXT NOT NULL DEFAULT '',
|
||||
url TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT -1,
|
||||
mtime INTEGER NOT NULL DEFAULT -1,
|
||||
ctime INTEGER NOT NULL DEFAULT -1,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
fingerprint TEXT DEFAULT '',
|
||||
fingerprint TEXT,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
@@ -59,15 +59,34 @@ CREATE TABLE device_%deviceid_songs (
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT DEFAULT '',
|
||||
art_manual TEXT DEFAULT '',
|
||||
art_embedded INTEGER DEFAULT 0,
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
art_unset INTEGER DEFAULT 0,
|
||||
|
||||
effective_albumartist TEXT DEFAULT '',
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT DEFAULT '',
|
||||
cue_path TEXT,
|
||||
|
||||
rating INTEGER DEFAULT -1
|
||||
rating INTEGER DEFAULT -1,
|
||||
|
||||
acoustid_id TEXT,
|
||||
acoustid_fingerprint TEXT,
|
||||
|
||||
musicbrainz_album_artist_id TEXT,
|
||||
musicbrainz_artist_id TEXT,
|
||||
musicbrainz_original_artist_id TEXT,
|
||||
musicbrainz_album_id TEXT,
|
||||
musicbrainz_original_album_id TEXT,
|
||||
musicbrainz_recording_id TEXT,
|
||||
musicbrainz_track_id TEXT,
|
||||
musicbrainz_disc_id TEXT,
|
||||
musicbrainz_release_group_id TEXT,
|
||||
musicbrainz_work_id TEXT,
|
||||
|
||||
ebur128_integrated_loudness_lufs REAL,
|
||||
ebur128_loudness_range_lu REAL
|
||||
|
||||
);
|
||||
|
||||
@@ -75,9 +94,4 @@ CREATE INDEX idx_device_%deviceid_songs_album ON device_%deviceid_songs (album);
|
||||
|
||||
CREATE INDEX idx_device_%deviceid_songs_comp_artist ON device_%deviceid_songs (compilation_effective, artist);
|
||||
|
||||
CREATE VIRTUAL TABLE device_%deviceid_fts USING fts5(
|
||||
ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
);
|
||||
|
||||
UPDATE devices SET schema_version=3 WHERE ROWID=%deviceid;
|
||||
UPDATE devices SET schema_version=5 WHERE ROWID=%deviceid;
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
ALTER TABLE playlist_items ADD COLUMN internet_service TEXT;
|
||||
|
||||
UPDATE schema_version SET version=1;
|
||||
@@ -1,4 +1,4 @@
|
||||
ALTER TABLE %allsongstables ADD COLUMN fingerprint TEXT DEFAULT '';
|
||||
ALTER TABLE %allsongstables ADD COLUMN fingerprint TEXT;
|
||||
|
||||
ALTER TABLE %allsongstables ADD COLUMN lastseen INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
CREATE TABLE IF NOT EXISTS radio_channels (
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
name TEXT DEFAULT '',
|
||||
url TEXT DEFAULT '',
|
||||
thumbnail_url TEXT DEFAULT ''
|
||||
name TEXT NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
thumbnail_url TEXT
|
||||
);
|
||||
|
||||
UPDATE schema_version SET version=15;
|
||||
|
||||
217
data/schema/schema-16.sql
Normal file
@@ -0,0 +1,217 @@
|
||||
ALTER TABLE songs ADD COLUMN acoustid_id TEXT;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN acoustid_fingerprint TEXT;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN musicbrainz_album_artist_id TEXT;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN musicbrainz_artist_id TEXT;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN musicbrainz_original_artist_id TEXT;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN musicbrainz_album_id TEXT;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN musicbrainz_original_album_id TEXT;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN musicbrainz_recording_id TEXT;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN musicbrainz_track_id TEXT;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN musicbrainz_disc_id TEXT;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN musicbrainz_release_group_id TEXT;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN musicbrainz_work_id TEXT;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN acoustid_id TEXT;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN acoustid_fingerprint TEXT;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_artist_id TEXT;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_album_id TEXT;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_original_album_id TEXT;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_recording_id TEXT;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_track_id TEXT;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_disc_id TEXT;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_release_group_id TEXT;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN musicbrainz_work_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN acoustid_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN acoustid_fingerprint TEXT;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_artist_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_album_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_original_album_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_recording_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_track_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_disc_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_release_group_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN musicbrainz_work_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN acoustid_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN acoustid_fingerprint TEXT;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_artist_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_album_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_original_album_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_recording_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_track_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_disc_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_release_group_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN musicbrainz_work_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN acoustid_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN acoustid_fingerprint TEXT;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_artist_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_album_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_original_album_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_recording_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_track_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_disc_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_release_group_id TEXT;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN musicbrainz_work_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN acoustid_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN acoustid_fingerprint TEXT;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_artist_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_album_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_original_album_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_recording_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_track_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_disc_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_release_group_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN musicbrainz_work_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN acoustid_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN acoustid_fingerprint TEXT;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_artist_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_album_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_original_album_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_recording_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_track_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_disc_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_release_group_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN musicbrainz_work_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN acoustid_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN acoustid_fingerprint TEXT;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_album_artist_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_artist_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_original_artist_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_album_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_original_album_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_recording_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_track_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_disc_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_release_group_id TEXT;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN musicbrainz_work_id TEXT;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN acoustid_id TEXT;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN acoustid_fingerprint TEXT;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN musicbrainz_album_artist_id TEXT;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN musicbrainz_artist_id TEXT;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN musicbrainz_original_artist_id TEXT;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN musicbrainz_album_id TEXT;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN musicbrainz_original_album_id TEXT;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN musicbrainz_recording_id TEXT;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN musicbrainz_track_id TEXT;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN musicbrainz_disc_id TEXT;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN musicbrainz_release_group_id TEXT;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN musicbrainz_work_id TEXT;
|
||||
|
||||
UPDATE schema_version SET version=16;
|
||||
45
data/schema/schema-17.sql
Normal file
@@ -0,0 +1,45 @@
|
||||
ALTER TABLE songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN art_unset INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN art_embedded INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN art_unset INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN art_embedded INTEGER DEFAULT 0;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN art_unset INTEGER DEFAULT 0;
|
||||
|
||||
UPDATE songs SET art_embedded = 1 WHERE art_automatic = 'file:(embedded)';
|
||||
|
||||
UPDATE songs SET art_automatic = '' WHERE art_automatic = 'file:(embedded)';
|
||||
|
||||
UPDATE songs SET art_unset = 1 WHERE art_manual = 'file:(unset)';
|
||||
|
||||
UPDATE songs SET art_manual = '' WHERE art_manual = 'file:(unset)';
|
||||
|
||||
UPDATE schema_version SET version=17;
|
||||
37
data/schema/schema-18.sql
Normal file
@@ -0,0 +1,37 @@
|
||||
ALTER TABLE songs ADD COLUMN ebur128_integrated_loudness_lufs REAL;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN ebur128_loudness_range_lu REAL;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN ebur128_integrated_loudness_lufs REAL;
|
||||
|
||||
ALTER TABLE subsonic_songs ADD COLUMN ebur128_loudness_range_lu REAL;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN ebur128_integrated_loudness_lufs REAL;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN ebur128_loudness_range_lu REAL;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN ebur128_integrated_loudness_lufs REAL;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN ebur128_loudness_range_lu REAL;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN ebur128_integrated_loudness_lufs REAL;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN ebur128_loudness_range_lu REAL;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN ebur128_integrated_loudness_lufs REAL;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs ADD COLUMN ebur128_loudness_range_lu REAL;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN ebur128_integrated_loudness_lufs REAL;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs ADD COLUMN ebur128_loudness_range_lu REAL;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN ebur128_integrated_loudness_lufs REAL;
|
||||
|
||||
ALTER TABLE qobuz_songs ADD COLUMN ebur128_loudness_range_lu REAL;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN ebur128_integrated_loudness_lufs REAL;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN ebur128_loudness_range_lu REAL;
|
||||
|
||||
UPDATE schema_version SET version=18;
|
||||
19
data/schema/schema-19.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
DROP TABLE IF EXISTS %allsongstables_fts;
|
||||
|
||||
DROP TABLE IF EXISTS songs_fts;
|
||||
|
||||
DROP TABLE IF EXISTS subsonic_songs_fts;
|
||||
|
||||
DROP TABLE IF EXISTS tidal_artists_songs_fts;
|
||||
|
||||
DROP TABLE IF EXISTS tidal_albums_songs_fts;
|
||||
|
||||
DROP TABLE IF EXISTS tidal_songs_fts;
|
||||
|
||||
DROP TABLE IF EXISTS qobuz_artists_songs_fts;
|
||||
|
||||
DROP TABLE IF EXISTS qobuz_albums_songs_fts;
|
||||
|
||||
DROP TABLE IF EXISTS qobuz_songs_fts;
|
||||
|
||||
UPDATE schema_version SET version=19;
|
||||
@@ -1,5 +0,0 @@
|
||||
ALTER TABLE songs ADD COLUMN lyrics TEXT;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN lyrics TEXT;
|
||||
|
||||
UPDATE schema_version SET version=2;
|
||||
244
data/schema/schema-20.sql
Normal file
@@ -0,0 +1,244 @@
|
||||
CREATE TABLE IF NOT EXISTS spotify_artists_songs (
|
||||
|
||||
title TEXT,
|
||||
album TEXT,
|
||||
artist TEXT,
|
||||
albumartist TEXT,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||
genre TEXT,
|
||||
compilation INTEGER NOT NULL DEFAULT 0,
|
||||
composer TEXT,
|
||||
performer TEXT,
|
||||
grouping TEXT,
|
||||
comment TEXT,
|
||||
lyrics TEXT,
|
||||
|
||||
artist_id TEXT,
|
||||
album_id TEXT,
|
||||
song_id TEXT,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||
url TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT -1,
|
||||
mtime INTEGER NOT NULL DEFAULT -1,
|
||||
ctime INTEGER NOT NULL DEFAULT -1,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
fingerprint TEXT,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
||||
lastseen INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_embedded INTEGER DEFAULT 0,
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
art_unset INTEGER DEFAULT 0,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT,
|
||||
|
||||
rating INTEGER DEFAULT -1,
|
||||
|
||||
acoustid_id TEXT,
|
||||
acoustid_fingerprint TEXT,
|
||||
|
||||
musicbrainz_album_artist_id TEXT,
|
||||
musicbrainz_artist_id TEXT,
|
||||
musicbrainz_original_artist_id TEXT,
|
||||
musicbrainz_album_id TEXT,
|
||||
musicbrainz_original_album_id TEXT,
|
||||
musicbrainz_recording_id TEXT,
|
||||
musicbrainz_track_id TEXT,
|
||||
musicbrainz_disc_id TEXT,
|
||||
musicbrainz_release_group_id TEXT,
|
||||
musicbrainz_work_id TEXT,
|
||||
|
||||
ebur128_integrated_loudness_lufs REAL,
|
||||
ebur128_loudness_range_lu REAL
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS spotify_albums_songs (
|
||||
|
||||
title TEXT,
|
||||
album TEXT,
|
||||
artist TEXT,
|
||||
albumartist TEXT,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||
genre TEXT,
|
||||
compilation INTEGER NOT NULL DEFAULT 0,
|
||||
composer TEXT,
|
||||
performer TEXT,
|
||||
grouping TEXT,
|
||||
comment TEXT,
|
||||
lyrics TEXT,
|
||||
|
||||
artist_id TEXT,
|
||||
album_id TEXT,
|
||||
song_id TEXT,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||
url TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT -1,
|
||||
mtime INTEGER NOT NULL DEFAULT -1,
|
||||
ctime INTEGER NOT NULL DEFAULT -1,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
fingerprint TEXT,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
||||
lastseen INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_embedded INTEGER DEFAULT 0,
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
art_unset INTEGER DEFAULT 0,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT,
|
||||
|
||||
rating INTEGER DEFAULT -1,
|
||||
|
||||
acoustid_id TEXT,
|
||||
acoustid_fingerprint TEXT,
|
||||
|
||||
musicbrainz_album_artist_id TEXT,
|
||||
musicbrainz_artist_id TEXT,
|
||||
musicbrainz_original_artist_id TEXT,
|
||||
musicbrainz_album_id TEXT,
|
||||
musicbrainz_original_album_id TEXT,
|
||||
musicbrainz_recording_id TEXT,
|
||||
musicbrainz_track_id TEXT,
|
||||
musicbrainz_disc_id TEXT,
|
||||
musicbrainz_release_group_id TEXT,
|
||||
musicbrainz_work_id TEXT,
|
||||
|
||||
ebur128_integrated_loudness_lufs REAL,
|
||||
ebur128_loudness_range_lu REAL
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS spotify_songs (
|
||||
|
||||
title TEXT,
|
||||
album TEXT,
|
||||
artist TEXT,
|
||||
albumartist TEXT,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT -1,
|
||||
genre TEXT,
|
||||
compilation INTEGER NOT NULL DEFAULT 0,
|
||||
composer TEXT,
|
||||
performer TEXT,
|
||||
grouping TEXT,
|
||||
comment TEXT,
|
||||
lyrics TEXT,
|
||||
|
||||
artist_id TEXT,
|
||||
album_id TEXT,
|
||||
song_id TEXT,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||
url TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT -1,
|
||||
mtime INTEGER NOT NULL DEFAULT -1,
|
||||
ctime INTEGER NOT NULL DEFAULT -1,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
fingerprint TEXT,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
||||
lastseen INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_embedded INTEGER DEFAULT 0,
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
art_unset INTEGER DEFAULT 0,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT,
|
||||
|
||||
rating INTEGER DEFAULT -1,
|
||||
|
||||
acoustid_id TEXT,
|
||||
acoustid_fingerprint TEXT,
|
||||
|
||||
musicbrainz_album_artist_id TEXT,
|
||||
musicbrainz_artist_id TEXT,
|
||||
musicbrainz_original_artist_id TEXT,
|
||||
musicbrainz_album_id TEXT,
|
||||
musicbrainz_original_album_id TEXT,
|
||||
musicbrainz_recording_id TEXT,
|
||||
musicbrainz_track_id TEXT,
|
||||
musicbrainz_disc_id TEXT,
|
||||
musicbrainz_release_group_id TEXT,
|
||||
musicbrainz_work_id TEXT,
|
||||
|
||||
ebur128_integrated_loudness_lufs REAL,
|
||||
ebur128_loudness_range_lu REAL
|
||||
|
||||
);
|
||||
|
||||
UPDATE schema_version SET version=20;
|
||||
@@ -1,65 +0,0 @@
|
||||
ALTER TABLE songs ADD COLUMN source INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
UPDATE songs SET source = 2 WHERE source = 0;
|
||||
|
||||
DROP TABLE playlist_items;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS playlist_items (
|
||||
|
||||
playlist INTEGER NOT NULL,
|
||||
type INTEGER NOT NULL DEFAULT 0,
|
||||
collection_id INTEGER,
|
||||
url TEXT,
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER,
|
||||
filename TEXT,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER,
|
||||
mtime INTEGER,
|
||||
ctime INTEGER,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
UPDATE schema_version SET version=3;
|
||||
@@ -1,205 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS tidal_artists_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL,
|
||||
filename TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT 0,
|
||||
mtime INTEGER NOT NULL DEFAULT 0,
|
||||
ctime INTEGER NOT NULL DEFAULT 0,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tidal_albums_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL,
|
||||
filename TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT 0,
|
||||
mtime INTEGER NOT NULL DEFAULT 0,
|
||||
ctime INTEGER NOT NULL DEFAULT 0,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tidal_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL,
|
||||
filename TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT 0,
|
||||
mtime INTEGER NOT NULL DEFAULT 0,
|
||||
ctime INTEGER NOT NULL DEFAULT 0,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE VIRTUAL TABLE IF NOT EXISTS tidal_artists_songs_fts USING fts3(
|
||||
|
||||
ftstitle,
|
||||
ftsalbum,
|
||||
ftsartist,
|
||||
ftsalbumartist,
|
||||
ftscomposer,
|
||||
ftsperformer,
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize=unicode
|
||||
|
||||
);
|
||||
|
||||
CREATE VIRTUAL TABLE IF NOT EXISTS tidal_albums_songs_fts USING fts3(
|
||||
|
||||
ftstitle,
|
||||
ftsalbum,
|
||||
ftsartist,
|
||||
ftsalbumartist,
|
||||
ftscomposer,
|
||||
ftsperformer,
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize=unicode
|
||||
|
||||
);
|
||||
|
||||
CREATE VIRTUAL TABLE IF NOT EXISTS tidal_songs_fts USING fts3(
|
||||
|
||||
ftstitle,
|
||||
ftsalbum,
|
||||
ftsartist,
|
||||
ftsalbumartist,
|
||||
ftscomposer,
|
||||
ftsperformer,
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize=unicode
|
||||
|
||||
);
|
||||
|
||||
UPDATE schema_version SET version=4;
|
||||
@@ -1,31 +0,0 @@
|
||||
ALTER TABLE songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE tidal_artists_songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE tidal_albums_songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE tidal_songs ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN artist_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN album_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
ALTER TABLE playlist_items ADD COLUMN song_id INTEGER NOT NULL DEFAULT -1;
|
||||
|
||||
UPDATE schema_version SET version=5;
|
||||
@@ -1,73 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS subsonic_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
||||
album_id INTEGER NOT NULL DEFAULT -1,
|
||||
song_id INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL,
|
||||
filename TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT 0,
|
||||
mtime INTEGER NOT NULL DEFAULT 0,
|
||||
ctime INTEGER NOT NULL DEFAULT 0,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE VIRTUAL TABLE IF NOT EXISTS subsonic_songs_fts USING fts3(
|
||||
|
||||
ftstitle,
|
||||
ftsalbum,
|
||||
ftsartist,
|
||||
ftsalbumartist,
|
||||
ftscomposer,
|
||||
ftsperformer,
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize=unicode
|
||||
|
||||
);
|
||||
|
||||
UPDATE schema_version SET version=6;
|
||||
@@ -1,217 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
||||
album_id INTEGER NOT NULL DEFAULT -1,
|
||||
song_id INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL,
|
||||
filename TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT 0,
|
||||
mtime INTEGER NOT NULL DEFAULT 0,
|
||||
ctime INTEGER NOT NULL DEFAULT 0,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
||||
album_id INTEGER NOT NULL DEFAULT -1,
|
||||
song_id INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL,
|
||||
filename TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT 0,
|
||||
mtime INTEGER NOT NULL DEFAULT 0,
|
||||
ctime INTEGER NOT NULL DEFAULT 0,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS qobuz_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
||||
album_id INTEGER NOT NULL DEFAULT -1,
|
||||
song_id INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT 0,
|
||||
samplerate INTEGER NOT NULL DEFAULT 0,
|
||||
bitdepth INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL,
|
||||
filename TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT 0,
|
||||
mtime INTEGER NOT NULL DEFAULT 0,
|
||||
ctime INTEGER NOT NULL DEFAULT 0,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE VIRTUAL TABLE IF NOT EXISTS qobuz_artists_songs_fts USING fts3(
|
||||
|
||||
ftstitle,
|
||||
ftsalbum,
|
||||
ftsartist,
|
||||
ftsalbumartist,
|
||||
ftscomposer,
|
||||
ftsperformer,
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize=unicode
|
||||
|
||||
);
|
||||
|
||||
CREATE VIRTUAL TABLE IF NOT EXISTS qobuz_albums_songs_fts USING fts3(
|
||||
|
||||
ftstitle,
|
||||
ftsalbum,
|
||||
ftsartist,
|
||||
ftsalbumartist,
|
||||
ftscomposer,
|
||||
ftsperformer,
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize=unicode
|
||||
|
||||
);
|
||||
|
||||
CREATE VIRTUAL TABLE IF NOT EXISTS qobuz_songs_fts USING fts3(
|
||||
|
||||
ftstitle,
|
||||
ftsalbum,
|
||||
ftsartist,
|
||||
ftsalbumartist,
|
||||
ftscomposer,
|
||||
ftsperformer,
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize=unicode
|
||||
|
||||
);
|
||||
|
||||
UPDATE schema_version SET version=7;
|
||||
@@ -1,595 +0,0 @@
|
||||
ALTER TABLE songs RENAME TO songs_old;
|
||||
|
||||
ALTER TABLE playlist_items RENAME TO playlist_items_old;
|
||||
|
||||
ALTER TABLE tidal_artists_songs RENAME TO tidal_artists_songs_old;
|
||||
|
||||
ALTER TABLE tidal_albums_songs RENAME TO tidal_albums_songs_old;
|
||||
|
||||
ALTER TABLE tidal_songs RENAME TO tidal_songs_old;
|
||||
|
||||
ALTER TABLE qobuz_artists_songs RENAME TO qobuz_artists_songs_old;
|
||||
|
||||
ALTER TABLE qobuz_albums_songs RENAME TO qobuz_albums_songs_old;
|
||||
|
||||
ALTER TABLE qobuz_songs RENAME TO qobuz_songs_old;
|
||||
|
||||
ALTER TABLE subsonic_songs RENAME TO subsonic_songs_old;
|
||||
|
||||
DROP INDEX idx_filename;
|
||||
|
||||
CREATE TABLE songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
||||
album_id TEXT NOT NULL,
|
||||
song_id INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||
url TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT -1,
|
||||
mtime INTEGER NOT NULL DEFAULT -1,
|
||||
ctime INTEGER NOT NULL DEFAULT -1,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE tidal_artists_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
||||
album_id TEXT NOT NULL,
|
||||
song_id INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||
url TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT -1,
|
||||
mtime INTEGER NOT NULL DEFAULT -1,
|
||||
ctime INTEGER NOT NULL DEFAULT -1,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE tidal_albums_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
||||
album_id TEXT NOT NULL,
|
||||
song_id INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||
url TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT -1,
|
||||
mtime INTEGER NOT NULL DEFAULT -1,
|
||||
ctime INTEGER NOT NULL DEFAULT -1,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE tidal_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
||||
album_id TEXT NOT NULL,
|
||||
song_id INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||
url TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT -1,
|
||||
mtime INTEGER NOT NULL DEFAULT -1,
|
||||
ctime INTEGER NOT NULL DEFAULT -1,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE subsonic_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
||||
album_id TEXT NOT NULL,
|
||||
song_id INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||
url TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT -1,
|
||||
mtime INTEGER NOT NULL DEFAULT -1,
|
||||
ctime INTEGER NOT NULL DEFAULT -1,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE qobuz_artists_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
||||
album_id TEXT NOT NULL,
|
||||
song_id INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||
url TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT -1,
|
||||
mtime INTEGER NOT NULL DEFAULT -1,
|
||||
ctime INTEGER NOT NULL DEFAULT -1,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE qobuz_albums_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
||||
album_id TEXT NOT NULL,
|
||||
song_id INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||
url TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT -1,
|
||||
mtime INTEGER NOT NULL DEFAULT -1,
|
||||
ctime INTEGER NOT NULL DEFAULT -1,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE qobuz_songs (
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
||||
album_id TEXT NOT NULL,
|
||||
song_id INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER NOT NULL DEFAULT -1,
|
||||
url TEXT NOT NULL,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER NOT NULL DEFAULT -1,
|
||||
mtime INTEGER NOT NULL DEFAULT -1,
|
||||
ctime INTEGER NOT NULL DEFAULT -1,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE playlist_items (
|
||||
|
||||
playlist INTEGER NOT NULL,
|
||||
type INTEGER NOT NULL DEFAULT 0,
|
||||
collection_id INTEGER,
|
||||
playlist_url TEXT,
|
||||
|
||||
title TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
albumartist TEXT NOT NULL,
|
||||
track INTEGER NOT NULL DEFAULT -1,
|
||||
disc INTEGER NOT NULL DEFAULT -1,
|
||||
year INTEGER NOT NULL DEFAULT -1,
|
||||
originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
genre TEXT NOT NULL,
|
||||
compilation INTEGER NOT NULL DEFAULT -1,
|
||||
composer TEXT NOT NULL,
|
||||
performer TEXT NOT NULL,
|
||||
grouping TEXT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
lyrics TEXT NOT NULL,
|
||||
|
||||
artist_id INTEGER NOT NULL DEFAULT -1,
|
||||
album_id TEXT NOT NULL,
|
||||
song_id INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
beginning INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
bitrate INTEGER NOT NULL DEFAULT -1,
|
||||
samplerate INTEGER NOT NULL DEFAULT -1,
|
||||
bitdepth INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
source INTEGER NOT NULL DEFAULT 0,
|
||||
directory_id INTEGER,
|
||||
url TEXT,
|
||||
filetype INTEGER NOT NULL DEFAULT 0,
|
||||
filesize INTEGER,
|
||||
mtime INTEGER,
|
||||
ctime INTEGER,
|
||||
unavailable INTEGER DEFAULT 0,
|
||||
|
||||
playcount INTEGER NOT NULL DEFAULT 0,
|
||||
skipcount INTEGER NOT NULL DEFAULT 0,
|
||||
lastplayed INTEGER NOT NULL DEFAULT -1,
|
||||
|
||||
compilation_detected INTEGER DEFAULT 0,
|
||||
compilation_on INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_off INTEGER NOT NULL DEFAULT 0,
|
||||
compilation_effective INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
art_automatic TEXT,
|
||||
art_manual TEXT,
|
||||
|
||||
effective_albumartist TEXT,
|
||||
effective_originalyear INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
cue_path TEXT
|
||||
|
||||
);
|
||||
|
||||
INSERT INTO songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
||||
FROM songs_old;
|
||||
|
||||
DROP TABLE songs_old;
|
||||
|
||||
INSERT INTO tidal_artists_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
||||
FROM tidal_artists_songs_old;
|
||||
|
||||
DROP TABLE tidal_artists_songs_old;
|
||||
|
||||
INSERT INTO tidal_albums_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
||||
FROM tidal_albums_songs_old;
|
||||
|
||||
DROP TABLE tidal_albums_songs_old;
|
||||
|
||||
INSERT INTO tidal_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
||||
FROM tidal_songs_old;
|
||||
|
||||
DROP TABLE tidal_songs_old;
|
||||
|
||||
INSERT INTO qobuz_artists_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
||||
FROM qobuz_artists_songs_old;
|
||||
|
||||
DROP TABLE qobuz_artists_songs_old;
|
||||
|
||||
INSERT INTO qobuz_albums_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
||||
FROM qobuz_albums_songs_old;
|
||||
|
||||
DROP TABLE qobuz_albums_songs_old;
|
||||
|
||||
INSERT INTO qobuz_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
||||
FROM qobuz_songs_old;
|
||||
|
||||
DROP TABLE qobuz_songs_old;
|
||||
|
||||
INSERT INTO subsonic_songs (title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
||||
SELECT title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
||||
FROM subsonic_songs_old;
|
||||
|
||||
DROP TABLE subsonic_songs_old;
|
||||
|
||||
INSERT INTO playlist_items (playlist, type, collection_id, playlist_url, title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path)
|
||||
SELECT playlist, type, collection_id, url, title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, artist_id, album_id, song_id, beginning, length, bitrate, samplerate, bitdepth, source, directory_id, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path
|
||||
FROM playlist_items_old;
|
||||
|
||||
DROP TABLE playlist_items_old;
|
||||
|
||||
CREATE INDEX idx_url ON songs (url);
|
||||
|
||||
UPDATE schema_version SET version=8;
|
||||
@@ -1,41 +0,0 @@
|
||||
DROP TABLE %allsongstables_fts;
|
||||
|
||||
DROP TABLE playlist_items_fts_;
|
||||
|
||||
CREATE VIRTUAL TABLE %allsongstables_fts USING fts5(
|
||||
|
||||
ftstitle,
|
||||
ftsalbum,
|
||||
ftsartist,
|
||||
ftsalbumartist,
|
||||
ftscomposer,
|
||||
ftsperformer,
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
CREATE VIRTUAL TABLE playlist_items_fts_ USING fts5(
|
||||
|
||||
ftstitle,
|
||||
ftsalbum,
|
||||
ftsartist,
|
||||
ftsalbumartist,
|
||||
ftscomposer,
|
||||
ftsperformer,
|
||||
ftsgrouping,
|
||||
ftsgenre,
|
||||
ftscomment,
|
||||
tokenize = "unicode61 remove_diacritics 1"
|
||||
|
||||
);
|
||||
|
||||
INSERT INTO %allsongstables_fts (ROWID, ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment)
|
||||
SELECT ROWID, title, album, artist, albumartist, composer, performer, grouping, genre, comment FROM %allsongstables;
|
||||
|
||||
INSERT INTO playlist_items_fts_ (ROWID, ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment)
|
||||
SELECT ROWID, title, album, artist, albumartist, composer, performer, grouping, genre, comment FROM playlist_items;
|
||||
|
||||
UPDATE schema_version SET version=9;
|
||||
13
data/style/dynamicplaylistcontrols.css
Normal file
@@ -0,0 +1,13 @@
|
||||
#container {
|
||||
background: %background;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(200, 200, 200, 75%);
|
||||
}
|
||||
|
||||
#label1 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#label2 {
|
||||
font-size: 7.5pt;
|
||||
}
|
||||
@@ -19,47 +19,6 @@
|
||||
background-clip: content;
|
||||
}
|
||||
|
||||
QToolButton {
|
||||
border: 2px solid transparent;
|
||||
border-radius: 3px;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
QToolButton::menu-button {
|
||||
width: 16px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
QToolButton[popupMode="1"] {
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
QToolButton:hover {
|
||||
border: 2px solid %palette-highlight;
|
||||
background-color: %palette-highlight-lighter;
|
||||
}
|
||||
|
||||
QToolButton:hover[popupMode="1"] {
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
QToolButton:pressed {
|
||||
border: 2px solid %palette-highlight-darker;
|
||||
background-color: %palette-highlight-lighter;
|
||||
}
|
||||
|
||||
QToolButton:pressed[popupMode="1"] {
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
macos {
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
macos QMenu {
|
||||
font-size: 13pt;
|
||||
}
|
||||
|
||||
#context-layout-container {
|
||||
background-color: %palette-base;
|
||||
}
|
||||
@@ -71,3 +30,37 @@ macos QMenu {
|
||||
#context-layout-scrollarea {
|
||||
background-color: %palette-base;
|
||||
}
|
||||
|
||||
#context-scrollarea {
|
||||
background-color: %palette-base;
|
||||
}
|
||||
|
||||
QToolButton[accessibleName="MenuPopupToolButton"] {
|
||||
border: 2px solid transparent;
|
||||
border-radius: 3px;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
QToolButton:hover[accessibleName="MenuPopupToolButton"] {
|
||||
border: 2px solid %palette-highlight;
|
||||
background-color: %palette-highlight-lighter;
|
||||
}
|
||||
|
||||
QToolButton:pressed[accessibleName="MenuPopupToolButton"] {
|
||||
border: 2px solid %palette-highlight-darker;
|
||||
background-color: %palette-highlight-lighter;
|
||||
}
|
||||
|
||||
QToolButton[popupMode="MenuButtonPopup"][accessibleName="MenuPopupToolButton"], QToolButton:hover[popupMode="MenuButtonPopup"][accessibleName="MenuPopupToolButton"], QToolButton:pressed[popupMode="MenuButtonPopup"][accessibleName="MenuPopupToolButton"] {
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
/* For backwards compatibility with Qt 5 as it does not support property name */
|
||||
QToolButton[popupMode="1"][accessibleName="MenuPopupToolButton"], QToolButton:hover[popupMode="1"][accessibleName="MenuPopupToolButton"], QToolButton:pressed[popupMode="1"][accessibleName="MenuPopupToolButton"] {
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
QToolButton::menu-button[accessibleName="MenuPopupToolButton"] {
|
||||
width: 16px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
10
debian/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
if(LSB_RELEASE_EXEC AND DPKG_BUILDPACKAGE)
|
||||
|
||||
execute_process(COMMAND env LC_ALL=C date "+%a, %-d %b %Y %H:%M:%S %z" OUTPUT_VARIABLE DEB_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -cs" OUTPUT_VARIABLE DEB_CODENAME OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
if(DEB_CODENAME AND DEB_DATE)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/changelog.in ${CMAKE_CURRENT_SOURCE_DIR}/changelog)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
35
debian/control
vendored
@@ -3,45 +3,45 @@ Section: sound
|
||||
Priority: optional
|
||||
Maintainer: Jonas Kvinge <jonas@jkvinge.net>
|
||||
Build-Depends: debhelper (>= 11),
|
||||
git,
|
||||
make,
|
||||
cmake,
|
||||
gcc,
|
||||
protobuf-compiler,
|
||||
g++,
|
||||
libglib2.0-dev,
|
||||
libdbus-1-dev,
|
||||
libgnutls28-dev,
|
||||
libprotobuf-dev,
|
||||
libboost-dev,
|
||||
libsqlite3-dev,
|
||||
libasound2-dev,
|
||||
libpulse-dev,
|
||||
libtag1-dev,
|
||||
qtbase5-dev,
|
||||
qtbase5-private-dev,
|
||||
qtbase5-dev-tools,
|
||||
qttools5-dev,
|
||||
libqt5x11extras5-dev,
|
||||
libicu-dev,
|
||||
qt6-base-dev,
|
||||
qt6-base-dev-tools,
|
||||
qt6-tools-dev,
|
||||
qt6-tools-dev-tools,
|
||||
qt6-l10n-tools,
|
||||
libgstreamer1.0-dev,
|
||||
libgstreamer-plugins-base1.0-dev,
|
||||
libcdio-dev,
|
||||
libgpod-dev,
|
||||
libmtp-dev,
|
||||
libchromaprint-dev,
|
||||
libfftw3-dev
|
||||
Standards-Version: 4.2.1
|
||||
libfftw3-dev,
|
||||
libebur128-dev
|
||||
Standards-Version: 4.6.1
|
||||
|
||||
Package: strawberry
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
libsqlite3-0,
|
||||
libqt5sql5-sqlite,
|
||||
libqt6sql6-sqlite,
|
||||
qt6-qpa-plugins,
|
||||
gstreamer1.0-plugins-base,
|
||||
gstreamer1.0-plugins-good,
|
||||
gstreamer1.0-alsa,
|
||||
gstreamer1.0-pulseaudio
|
||||
Homepage: http://www.strawberrymusicplayer.org/
|
||||
Description: Audio player and music collection organizer
|
||||
Description: music player and music collection organizer
|
||||
Strawberry is a music player aimed at music collectors and audiophiles.
|
||||
.
|
||||
Features:
|
||||
@@ -49,14 +49,13 @@ Description: Audio player and music collection organizer
|
||||
- Supports WAV, FLAC, WavPack, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF
|
||||
- Audio CD playback
|
||||
- Native desktop notifications
|
||||
- Playlist management
|
||||
- Playlists in multiple formats
|
||||
- Playlist management and playlists in multiple formats
|
||||
- Smart and dynamic playlists
|
||||
- Advanced audio output and device configuration for bit-perfect playback on Linux
|
||||
- Edit tags on audio files
|
||||
- Automatically retrieve tags from MusicBrainz
|
||||
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
|
||||
- Song lyrics from AudD, Genius, Musixmatch, ChartLyrics, lyrics.ovh and lololyrics.com
|
||||
- Support for multiple backends
|
||||
- Song lyrics from Genius, Musixmatch, ChartLyrics, lyrics.ovh, lololyrics.com, songlyrics.com, azlyrics.com and elyrics.net
|
||||
- Audio analyzer
|
||||
- Audio equalizer
|
||||
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
|
||||
|
||||
248
debian/copyright
vendored
@@ -1,46 +1,48 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: strawberry
|
||||
Upstream-Contact: Jonas Kvinge <jonas@jkvinge.net>
|
||||
Source: https://www.strawberrymusicplayer.org/
|
||||
Source: https://github.com/strawberrymusicplayer/strawberry
|
||||
|
||||
Files: *
|
||||
Copyright: 2010-2015, David Sansome <me@davidsansome.com>
|
||||
2012-2014, 2017-2024 Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/core/timeconstants.h
|
||||
ext/libstrawberry-common/core/logging.cpp
|
||||
ext/libstrawberry-common/core/logging.h
|
||||
ext/libstrawberry-common/core/messagehandler.cpp
|
||||
ext/libstrawberry-common/core/messagehandler.h
|
||||
Files: src/utilities/timeconstants.h
|
||||
src/core/logging.cpp
|
||||
src/core/logging.h
|
||||
Copyright: 2011, 2012, David Sansome <me@davidsansome.com>
|
||||
2018-2022, Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: Apache-2.0
|
||||
|
||||
Files: src/core/main.h
|
||||
src/core/iconloader.cpp
|
||||
src/core/iconloader.h
|
||||
src/core/iconmapper.h
|
||||
src/config.h.in
|
||||
src/version.h.in
|
||||
src/context/contextview.cpp
|
||||
src/context/contextview.h
|
||||
src/context/contextalbum.cpp
|
||||
src/context/contextalbum.h
|
||||
src/engine/enginetype.cpp
|
||||
src/engine/enginetype.h
|
||||
src/engine/alsadevicefinder.cpp
|
||||
src/engine/alsadevicefinder.h
|
||||
src/engine/alsapcmdevicefinder.cpp
|
||||
src/engine/alsapcmdevicefinder.h
|
||||
src/engine/mmdevicefinder.cpp
|
||||
src/engine/mmdevicefinder.h
|
||||
src/engine/uwpdevicefinder.cpp
|
||||
src/engine/uwpdevicefinder.h
|
||||
src/engine/devicefinder.cpp
|
||||
src/engine/devicefinder.h
|
||||
src/engine/enginedevice.cpp
|
||||
src/engine/enginedevice.h
|
||||
src/internet/internetservice.cpp
|
||||
src/internet/internetservice.h
|
||||
src/internet/internettabsview.cpp
|
||||
src/internet/internettabsview.h
|
||||
src/internet/internetsongsview.cpp
|
||||
src/internet/internetsongsview.h
|
||||
src/engine/enginemetadata.cpp
|
||||
src/engine/enginemetadata.h
|
||||
src/streaming/streamingservice.cpp
|
||||
src/streaming/streamingservice.h
|
||||
src/streaming/streamingtabsview.cpp
|
||||
src/streaming/streamingtabsview.h
|
||||
src/streaming/streamingsongsview.cpp
|
||||
src/streaming/streamingsongsview.h
|
||||
src/settings/backendsettingspage.cpp
|
||||
src/settings/backendsettingspage.h
|
||||
src/settings/coverssettingspage.cpp
|
||||
@@ -53,6 +55,8 @@ Files: src/core/main.h
|
||||
src/settings/subsonicsettingspage.h
|
||||
src/settings/tidalsettingspage.cpp
|
||||
src/settings/tidalsettingspage.h
|
||||
src/settings/spotifysettingspage.cpp
|
||||
src/settings/spotifysettingspage.h
|
||||
src/covermanager/jsoncoverprovider.cpp
|
||||
src/covermanager/jsoncoverprovider.h
|
||||
src/covermanager/lastfmcoverprovider.cpp
|
||||
@@ -63,17 +67,23 @@ Files: src/core/main.h
|
||||
src/covermanager/deezercoverprovider.h
|
||||
src/covermanager/tidalcoverprovider.cpp
|
||||
src/covermanager/tidalcoverprovider.h
|
||||
src/covermanager/opentidalcoverprovider.cpp
|
||||
src/covermanager/opentidalcoverprovider.h
|
||||
src/covermanager/qobuzcoverprovider.cpp
|
||||
src/covermanager/qobuzcoverprovider.h
|
||||
src/covermanager/spotifycoverprovider.cpp
|
||||
src/covermanager/spotifycoverprovider.h
|
||||
src/covermanager/musixmatchcoverprovider.cpp
|
||||
src/covermanager/musixmatchcoverprovider.h
|
||||
src/globalshortcuts/globalshortcutsbackend-system.cpp
|
||||
src/globalshortcuts/globalshortcutsbackend-system.h
|
||||
src/globalshortcuts/globalshortcutsbackend-kglobalaccel.cpp
|
||||
src/globalshortcuts/globalshortcutsbackend-kglobalaccel.h
|
||||
src/globalshortcuts/globalshortcutsbackend-x11.cpp
|
||||
src/globalshortcuts/globalshortcutsbackend-x11.h
|
||||
src/globalshortcuts/globalshortcutsbackend-win.cpp
|
||||
src/globalshortcuts/globalshortcutsbackend-win.h
|
||||
src/globalshortcuts/globalshortcut.cpp
|
||||
src/globalshortcuts/globalshortcut.h
|
||||
src/globalshortcuts/globalshortcut-X11.cpp
|
||||
src/globalshortcuts/globalshortcut-x11.cpp
|
||||
src/globalshortcuts/globalshortcut-win.cpp
|
||||
src/globalshortcuts/keymapper_x11.h
|
||||
src/globalshortcuts/keymapper_win.h
|
||||
@@ -81,132 +91,21 @@ Files: src/core/main.h
|
||||
src/scrobbler/*
|
||||
src/subsonic/*
|
||||
src/tidal/*
|
||||
src/qobuz/*
|
||||
src/radios/*
|
||||
src/spotify/*
|
||||
src/transcoder/transcoderoptionswavpack.cpp
|
||||
src/transcoder/transcoderoptionswavpack.h
|
||||
Copyright: 2012-2014, 2017-2020, Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/core/main.cpp
|
||||
src/core/mainwindow.cpp
|
||||
src/core/mainwindow.h
|
||||
src/core/player.cpp
|
||||
src/core/player.h
|
||||
src/core/song.cpp
|
||||
src/core/song.h
|
||||
src/core/songloader.cpp
|
||||
src/core/songloader.h
|
||||
src/core/urlhandler.cpp
|
||||
src/core/urlhandler.h
|
||||
src/core/utilities.cpp
|
||||
src/core/utilities.h
|
||||
src/core/networkaccessmanager.cpp
|
||||
src/core/networkaccessmanager.h
|
||||
src/core/threadsafenetworkdiskcache.cpp
|
||||
src/core/threadsafenetworkdiskcache.h
|
||||
src/core/filesystemmusicstorage.cpp
|
||||
src/core/filesystemmusicstorage.h
|
||||
src/core/stylesheetloader.cpp
|
||||
src/core/stylesheetloader.h
|
||||
src/engine/gstenginepipeline.cpp
|
||||
src/engine/gstenginepipeline.h
|
||||
src/engine/vlcengine.cpp
|
||||
src/engine/vlcengine.h
|
||||
src/collection/collectionwatcher.cpp
|
||||
src/collection/collectionwatcher.h
|
||||
src/collection/collectionbackend.cpp
|
||||
src/collection/collectionbackend.h
|
||||
src/collection/collectionmodel.cpp
|
||||
src/collection/collectionmodel.h
|
||||
src/context/contextalbumsmodel.cpp
|
||||
src/context/contextalbumsview.cpp
|
||||
src/context/contextalbumsmodel.h
|
||||
src/context/contextalbumsview.h
|
||||
src/widgets/playingwidget.cpp
|
||||
src/widgets/playingwidget.h
|
||||
src/osd/osdbase.cpp
|
||||
src/osd/osdbase.h
|
||||
src/osd/osdpretty.cpp
|
||||
src/osd/osdpretty.h
|
||||
src/osd/osddbus.cpp
|
||||
src/osd/osddbus.h
|
||||
src/osd/osdmac.cpp
|
||||
src/osd/osdmac.h
|
||||
src/dialogs/about.cpp
|
||||
src/dialogs/about.h
|
||||
src/playlist/playlist.cpp
|
||||
src/playlist/playlist.h
|
||||
src/playlist/playlistitem.cpp
|
||||
src/playlist/playlistitem.h
|
||||
src/playlist/playlistdelegates.cpp
|
||||
src/playlist/playlistdelegates.h
|
||||
src/playlist/playlistbackend.cpp
|
||||
src/playlist/playlistbackend.h
|
||||
src/playlist/playlistview.cpp
|
||||
src/playlist/playlistview.h
|
||||
src/playlist/songplaylistitem.cpp
|
||||
src/playlist/songplaylistitem.h
|
||||
src/internet/internetplaylistitem.cpp
|
||||
src/internet/internetsearch.cpp
|
||||
src/internet/internetsearch.h
|
||||
src/internet/internetsearchview.cpp
|
||||
src/internet/internetsearchview.h
|
||||
src/internet/internetservices.cpp
|
||||
src/internet/internetservices.h
|
||||
src/internet/internetsongsview.cpp
|
||||
src/internet/internetsongsview.h
|
||||
src/internet/internetcollectionview.cpp
|
||||
src/internet/internetcollectionview.h
|
||||
ext/libstrawberry-tagreader/tagreader.cpp
|
||||
ext/libstrawberry-tagreader/tagreader.h
|
||||
src/device/devicemanager.cpp
|
||||
src/device/devicemanager.h
|
||||
src/device/deviceinfo.cpp
|
||||
src/device/deviceinfo.h
|
||||
src/device/deviceproperties.cpp
|
||||
src/device/deviceproperties.h
|
||||
src/device/deviceview.cpp
|
||||
src/device/deviceview.h
|
||||
src/device/connecteddevice.cpp
|
||||
src/device/connecteddevice.h
|
||||
src/device/mtpconnection.cpp
|
||||
src/device/mtpconnection.h
|
||||
src/device/mtpdevice.cpp
|
||||
src/device/mtpdevice.h
|
||||
src/globalshortcuts/globalshortcutsmanager.cpp
|
||||
src/globalshortcuts/globalshortcutsmanager.h
|
||||
src/settings/shortcutssettingspage.cpp
|
||||
src/settings/shortcutssettingspage.h
|
||||
src/settings/appearancesettingspage.cpp
|
||||
src/settings/appearancesettingspage.h
|
||||
src/organize/organize.cpp
|
||||
src/organize/organize.h
|
||||
src/organize/organizedialog.cpp
|
||||
src/organize/organizedialog.h
|
||||
src/organize/organizeerrordialog.cpp
|
||||
src/organize/organizeerrordialog.h
|
||||
src/transcoder/transcoder.cpp
|
||||
src/transcoder/transcoder.h
|
||||
src/musicbrainz/musicbrainzclient.cpp
|
||||
src/musicbrainz/musicbrainzclient.h
|
||||
src/covermanager/albumcoverloader.cpp
|
||||
src/covermanager/albumcoverloader.h
|
||||
src/covermanager/currentalbumcoverloader.cpp
|
||||
src/covermanager/currentalbumcoverloader.h
|
||||
src/covermanager/albumcoverchoicecontroller.cpp
|
||||
src/covermanager/albumcoverchoicecontroller.h
|
||||
src/covermanager/albumcoverfetchersearch.cpp
|
||||
src/covermanager/albumcoverfetchersearch.h
|
||||
src/covermanager/coverproviders.cpp
|
||||
src/covermanager/coverproviders.h
|
||||
src/covermanager/coverprovider.cpp
|
||||
src/covermanager/coverprovider.h
|
||||
Copyright: 2010, 2012-2014 David Sansome <me@davidsansome.com>
|
||||
2012-2014, 2017-2020 Jonas Kvinge <jonas@jkvinge.net>
|
||||
src/widgets/resizabletextedit.cpp
|
||||
src/widgets/resizabletextedit.h
|
||||
src/widgets/fancytabdata.cpp
|
||||
src/widgets/fancytabdata.h
|
||||
Copyright: 2012-2014, 2017-2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/engine/enginebase.cpp
|
||||
src/engine/enginebase.h
|
||||
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
Copyright: 2017-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||
2010, David Sansome <me@davidsansome.com>
|
||||
2004, 2005, Max Howell, <max.howell@methylblue.com>
|
||||
2003, Mark Kretschmann <markey@web.de>
|
||||
@@ -214,7 +113,7 @@ License: GPL-3+
|
||||
|
||||
Files: src/engine/gstengine.cpp
|
||||
src/engine/gstengine.h
|
||||
Copyright: 2017, 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
Copyright: 2017-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||
2006, Paul Cifarelli <paul@cifarelli.net>
|
||||
2005, Jakub Stachowski <qbast@go2.pl>
|
||||
2003-2005, Mark Kretschmann <markey@web.de>
|
||||
@@ -222,6 +121,8 @@ License: GPL-2+
|
||||
|
||||
Files: src/widgets/fancytabwidget.cpp
|
||||
src/widgets/fancytabwidget.h
|
||||
src/widgets/fancytabbar.cpp
|
||||
src/widgets/fancytabbar.h
|
||||
Copyright: 2018, Vikram Ambrose <ambroseworks@gmail.com>
|
||||
2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: GPL-3+
|
||||
@@ -230,12 +131,7 @@ Files: src/core/application.cpp
|
||||
src/core/application.h
|
||||
Copyright: 2012, David Sansome <me@davidsansome.com>
|
||||
2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||
2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/core/appearance.cpp
|
||||
src/core/appearance.h
|
||||
Copyright: 2012, Arnaud Bienner <arnaud.bienner@gmail.com>
|
||||
2018-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/covermanager/discogscoverprovider.cpp
|
||||
@@ -244,13 +140,7 @@ Copyright: 2012, Martin Björklund <mbj4668@gmail.com>
|
||||
2016, Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: GPL-3+
|
||||
|
||||
Files: ext/libstrawberry-common/core/arraysize.h
|
||||
ext/libstrawberry-common/core/scoped_nsautorelease_pool.h
|
||||
ext/libstrawberry-common/core/scoped_nsautorelease_pool.mm
|
||||
Copyright: 2010, 2011, 2014, The Chromium Authors.
|
||||
License: BSD-style
|
||||
|
||||
Files: ext/libstrawberry-common/core/lazy.h
|
||||
Files: src/core/lazy.h
|
||||
Copyright: 2016, John Maguire <john.maguire@gmail.com>
|
||||
License: GPL-3+
|
||||
|
||||
@@ -298,12 +188,16 @@ Copyright: 2011, Tyler Rhodes <tyler.s.rhodes@gmail.com>
|
||||
2015, Arun Narayanankutty <n.arun.lifescience@gmail.com>
|
||||
License: GPL-2+
|
||||
|
||||
Files: src/collection/savedgroupingmanager.h
|
||||
Files: src/collection/savedgroupingmanager.*
|
||||
Copyright: 2015, Nick Lanham <nick@afternight.org>
|
||||
2019-2021 Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/core/scoped_cftyperef.h
|
||||
Files: src/core/arraysize.h
|
||||
src/core/scoped_cftyperef.h
|
||||
src/core/scoped_nsobject.h
|
||||
src/core/scoped_nsautorelease_pool.h
|
||||
src/core/scoped_nsautorelease_pool.mm
|
||||
Copyright: 2010, 2011, 2014, The Chromium Authors.
|
||||
License: BSD-style
|
||||
|
||||
@@ -318,11 +212,11 @@ Files: src/device/udisks2lister.cpp
|
||||
Copyright: 2016, Valeriy Malov <jazzvoid@gmail.com>
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/internet/localredirectserver.cpp
|
||||
src/internet/localredirectserver.h
|
||||
Files: src/core/localredirectserver.cpp
|
||||
src/core/localredirectserver.h
|
||||
Copyright: 2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||
2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
2018-2019, Jonas Kvinge <jonas@jkvinge.net>
|
||||
2018-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/transcoder/transcoderoptionsopus.cpp
|
||||
@@ -337,37 +231,47 @@ Files: src/widgets/clickablelabel.cpp
|
||||
Copyright: 2010, 2011, Andrea Decorte <adecorte@gmail.com>
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/widgets/sliderwidget.cpp
|
||||
src/widgets/sliderwidget.h
|
||||
Copyright: 2005, Gábor Lehel
|
||||
Files: src/widgets/sliderslider.cpp
|
||||
src/widgets/sliderslider.h
|
||||
src/widgets/prettyslider.cpp
|
||||
src/widgets/prettyslider.h
|
||||
src/widgets/volumeslider.cpp
|
||||
src/widgets/volumeslider.h
|
||||
Copyright: 2018-2023, Jonas Kvinge <jonas@jkvinge.net>
|
||||
2005, Gábor Lehel
|
||||
2003, Mark Kretschmann <markey@web.de>
|
||||
License: GPL-2+
|
||||
|
||||
Files: src/scrobbler/subsonicscrobbler.*
|
||||
Copyright: 2018-2021 Jonas Kvinge <jonas@jkvinge.net>
|
||||
2020 Pascal Below <spezifisch@below.fr>
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/core/stylehelper.cpp
|
||||
src/core/stylehelper.h
|
||||
Copyright: 2016 The Qt Company Ltd.
|
||||
License: GPL-3+
|
||||
|
||||
Files: ext/gstmoodbar/gstfastspectrum.cpp
|
||||
ext/gstmoodbar/gstfastspectrum.h
|
||||
Files: 3rdparty/gstfastspectrum/gstfastspectrum.cpp
|
||||
3rdparty/gstfastspectrum/gstfastspectrum.h
|
||||
Copyright: 1999 Erik Walthinsen <omega@cse.ogi.edu>
|
||||
2006,2011 Stefan Kost <ensonic@users.sf.net>
|
||||
2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
2018-2024 Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: GPL-2+
|
||||
|
||||
Files: src/widgets/qsearchfield_nonmac.cpp
|
||||
Files: src/widgets/qsearchfield_qt.cpp
|
||||
src/widgets/qsearchfield_mac.mm
|
||||
src/widgets/qsearchfield.h
|
||||
src/widgets/qocoa_mac.h
|
||||
src/widgets/searchfield_qt_private.cpp
|
||||
src/widgets/searchfield_qt_private.h
|
||||
Copyright: 2011, Mike McQuaid <mike@mikemcquaid.com>
|
||||
2018-2024, Jonas Kvinge <jonas@jkvinge.net>
|
||||
License: Expat
|
||||
|
||||
Files: 3rdparty/SPMediaKeyTap/*
|
||||
Copyright: 2010, Spotify AB
|
||||
2011, Joachim Bengtsson
|
||||
License: BSD-3-clause
|
||||
|
||||
Files: 3rdparty/singleapplication/*
|
||||
Copyright: 2015-2018, Itay Grudev
|
||||
Files: 3rdparty/kdsingleapplication/*
|
||||
Copyright: 2019-2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
License: MIT
|
||||
|
||||
|
||||
@@ -475,7 +379,7 @@ License: Apache-2.0
|
||||
On Debian systems, the complete text of the Apache 2.0 license can be
|
||||
found in the file
|
||||
`/usr/share/common-licenses/Apache-2.0`.
|
||||
|
||||
|
||||
License: BSD-3-clause
|
||||
Copyright (c) The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
6
debian/copyright-scan-patterns.yml
vendored
@@ -4,14 +4,14 @@ ignore:
|
||||
- Changelog
|
||||
- COPYING
|
||||
- CMakeLists.txt
|
||||
- Dockerfile
|
||||
- cmake_uninstall.cmake.in
|
||||
- .clang-format
|
||||
- .gitignore
|
||||
- .travis.yml
|
||||
- .github
|
||||
- /debian/
|
||||
- /cmake/
|
||||
- /data/
|
||||
- /dist/
|
||||
- /snap/
|
||||
|
||||
suffixes:
|
||||
- jpg
|
||||
|
||||
1
debian/rules
vendored
@@ -5,7 +5,6 @@
|
||||
|
||||
override_dh_auto_clean:
|
||||
rm -f dist/macos/Info.plist
|
||||
rm -f dist/unix/PKGBUILD
|
||||
rm -f dist/unix/strawberry.spec
|
||||
rm -f dist/scripts/maketarball.sh
|
||||
rm -f dist/windows/strawberry.nsi
|
||||
|
||||
14
dist/CMakeLists.txt
vendored
@@ -2,17 +2,19 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/maketarball.sh.in ${CMAKE_CUR
|
||||
if(RPM_DISTRO AND RPM_DATE)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/unix/strawberry.spec @ONLY)
|
||||
endif(RPM_DISTRO AND RPM_DATE)
|
||||
if(DEB_CODENAME AND DEB_DATE)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/debian/changelog.in ${CMAKE_SOURCE_DIR}/debian/changelog)
|
||||
endif(DEB_CODENAME AND DEB_DATE)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/unix/PKGBUILD.in ${CMAKE_CURRENT_SOURCE_DIR}/unix/PKGBUILD @ONLY)
|
||||
|
||||
if(APPLE)
|
||||
if(DEFINED ENV{MACOSX_DEPLOYMENT_TARGET})
|
||||
set(LSMinimumSystemVersion $ENV{MACOSX_DEPLOYMENT_TARGET})
|
||||
else()
|
||||
set(LSMinimumSystemVersion 12.0)
|
||||
endif()
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist)
|
||||
endif(APPLE)
|
||||
|
||||
if(WIN32)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry.nsi.in ${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry.nsi @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/windres.rc.in ${CMAKE_BINARY_DIR}/windres.rc)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry.nsi.in ${CMAKE_BINARY_DIR}/strawberry.nsi @ONLY)
|
||||
endif(WIN32)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
@@ -21,7 +23,7 @@ if(UNIX AND NOT APPLE)
|
||||
install(FILES ../data/icons/128x128/strawberry.png DESTINATION share/icons/hicolor/128x128/apps/)
|
||||
install(FILES unix/org.strawberrymusicplayer.strawberry.desktop DESTINATION share/applications)
|
||||
install(FILES unix/org.strawberrymusicplayer.strawberry.appdata.xml DESTINATION share/metainfo)
|
||||
install(FILES unix/strawberry.1 unix/strawberry-tagreader.1 DESTINATION share/man/man1)
|
||||
install(FILES unix/strawberry.1 DESTINATION share/man/man1)
|
||||
endif(UNIX AND NOT APPLE)
|
||||
|
||||
if(APPLE)
|
||||
|
||||
2
dist/macos/Info.plist.in
vendored
@@ -33,7 +33,7 @@
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.music</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.13.4</string>
|
||||
<string>@LSMinimumSystemVersion@</string>
|
||||
<key>SUFeedURL</key>
|
||||
<string>https://www.strawberrymusicplayer.org/sparkle-macos</string>
|
||||
<key>SUPublicEDKey</key>
|
||||
|
||||
185
dist/macos/macgstcopy.sh
vendored
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Script to copy gstreamer plugins before macdeployqt is run.
|
||||
# Script to copy gio modules and gstreamer plugins before macdeployqt is run.
|
||||
|
||||
if [ "$1" = "" ]; then
|
||||
echo "Usage: $0 <bundledir>"
|
||||
@@ -8,100 +8,145 @@ if [ "$1" = "" ]; then
|
||||
fi
|
||||
bundledir=$1
|
||||
|
||||
if [ "$GIO_EXTRA_MODULES" = "" ]; then
|
||||
echo "Error: Set the GIO_EXTRA_MODULES environment variable to the path containing libgiognutls.so."
|
||||
if [ "${GIO_EXTRA_MODULES}" = "" ]; then
|
||||
echo "Error: Set the GIO_EXTRA_MODULES environment variable to the path containing gio modules."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$GST_PLUGIN_SCANNER" = "" ]; then
|
||||
if [ "${GST_PLUGIN_SCANNER}" = "" ]; then
|
||||
echo "Error: Set the GST_PLUGIN_SCANNER environment variable to the gst-plugin-scanner."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$GST_PLUGIN_PATH" = "" ]; then
|
||||
if [ "${GST_PLUGIN_PATH}" = "" ]; then
|
||||
echo "Error: Set the GST_PLUGIN_PATH environment variable to the path containing gstreamer plugins."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -e "${GIO_EXTRA_MODULES}/libgiognutls.so" ] && ! [ -e "${GIO_EXTRA_MODULES}/libgioopenssl.so" ]; then
|
||||
echo "Error: Missing ${GIO_EXTRA_MODULES}/libgiognutls.so or ${GIO_EXTRA_MODULES}/libgioopenssl.so."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -e "${GST_PLUGIN_SCANNER}" ]; then
|
||||
echo "Error: Missing ${GST_PLUGIN_SCANNER}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -d "${GST_PLUGIN_PATH}" ]; then
|
||||
echo "Error: GStreamer plugins path ${GST_PLUGIN_PATH} does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -e "${GST_PLUGIN_PATH}/libgstcoreelements.so" ] && ! [ -e "${GST_PLUGIN_PATH}/libgstcoreelements.dylib" ]; then
|
||||
echo "Error: Missing libgstcoreelements.{so,dylib} in GStreamer plugins path ${GST_PLUGIN_PATH}."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${bundledir}/Contents/PlugIns/gio-modules" || exit 1
|
||||
mkdir -p "${bundledir}/Contents/PlugIns/gstreamer" || exit 1
|
||||
|
||||
if ! [ -f "${GIO_EXTRA_MODULES}/libgiognutls.so" ]; then
|
||||
echo "Error: Missing ${GIO_EXTRA_MODULES}/libgiognutls.so."
|
||||
exit 1
|
||||
if [ -e "${GIO_EXTRA_MODULES}/libgiognutls.so" ]; then
|
||||
cp -v -f "${GIO_EXTRA_MODULES}/libgiognutls.so" "${bundledir}/Contents/PlugIns/gio-modules/" || exit 1
|
||||
else
|
||||
echo "Warning: Missing ${GIO_EXTRA_MODULES}/libgiognutls.so."
|
||||
fi
|
||||
cp -v -f "${GIO_EXTRA_MODULES}/libgiognutls.so" "${bundledir}/Contents/PlugIns/gio-modules/" || exit 1
|
||||
|
||||
if ! [ -f "${GST_PLUGIN_SCANNER}" ]; then
|
||||
echo "Error: Missing ${GST_PLUGIN_SCANNER}"
|
||||
exit 1
|
||||
if [ -e "${GIO_EXTRA_MODULES}/libgioopenssl.so" ]; then
|
||||
cp -v -f "${GIO_EXTRA_MODULES}/libgioopenssl.so" "${bundledir}/Contents/PlugIns/gio-modules/" || exit 1
|
||||
else
|
||||
echo "Warning: Missing ${GIO_EXTRA_MODULES}/libgioopenssl.so"
|
||||
fi
|
||||
|
||||
cp -v -f "${GST_PLUGIN_SCANNER}" "${bundledir}/Contents/PlugIns/" || exit 1
|
||||
install_name_tool -add_rpath "@loader_path/../Frameworks" "${bundledir}/Contents/PlugIns/$(basename ${GST_PLUGIN_SCANNER})" || exit 1
|
||||
|
||||
gst_plugins="
|
||||
libgstapetag.dylib
|
||||
libgstapp.dylib
|
||||
libgstaudioconvert.dylib
|
||||
libgstaudiofx.dylib
|
||||
libgstaudiomixer.dylib
|
||||
libgstaudioparsers.dylib
|
||||
libgstaudiorate.dylib
|
||||
libgstaudioresample.dylib
|
||||
libgstaudiotestsrc.dylib
|
||||
libgstaudiovisualizers.dylib
|
||||
libgstauparse.dylib
|
||||
libgstautoconvert.dylib
|
||||
libgstautodetect.dylib
|
||||
libgstcoreelements.dylib
|
||||
libgstequalizer.dylib
|
||||
libgstgio.dylib
|
||||
libgsticydemux.dylib
|
||||
libgstid3demux.dylib
|
||||
libgstlevel.dylib
|
||||
libgstosxaudio.dylib
|
||||
libgstplayback.dylib
|
||||
libgstrawparse.dylib
|
||||
libgstreplaygain.dylib
|
||||
libgstsoup.dylib
|
||||
libgstspectrum.dylib
|
||||
libgsttypefindfunctions.dylib
|
||||
libgstvolume.dylib
|
||||
libgstxingmux.dylib
|
||||
libgsttcp.dylib
|
||||
libgstudp.dylib
|
||||
libgstpbtypes.dylib
|
||||
libgstrtp.dylib
|
||||
libgstrtsp.dylib
|
||||
libgstflac.dylib
|
||||
libgstwavparse.dylib
|
||||
libgstfaad.dylib
|
||||
libgstogg.dylib
|
||||
libgstopus.dylib
|
||||
libgstasf.dylib
|
||||
libgstspeex.dylib
|
||||
libgsttaglib.dylib
|
||||
libgstvorbis.dylib
|
||||
libgstisomp4.dylib
|
||||
libgstlibav.dylib
|
||||
libgstaiff.dylib
|
||||
libgstlame.dylib
|
||||
libgstopusparse.dylib
|
||||
libgstfaac.dylib
|
||||
libgstmusepack.dylib
|
||||
libgstadaptivedemux2
|
||||
libgstaes
|
||||
libgstaiff
|
||||
libgstapetag
|
||||
libgstapp
|
||||
libgstasf
|
||||
libgstasfmux
|
||||
libgstaudioconvert
|
||||
libgstaudiofx
|
||||
libgstaudioparsers
|
||||
libgstaudioresample
|
||||
libgstautodetect
|
||||
libgstbs2b
|
||||
libgstcdio
|
||||
libgstcoreelements
|
||||
libgstdash
|
||||
libgstdsd
|
||||
libgstequalizer
|
||||
libgstfaac
|
||||
libgstfaad
|
||||
libgstfdkaac
|
||||
libgstflac
|
||||
libgstgio
|
||||
libgsthls
|
||||
libgsticydemux
|
||||
libgstid3demux
|
||||
libgstid3tag
|
||||
libgstisomp4
|
||||
libgstlame
|
||||
libgstmpegpsdemux
|
||||
libgstmpegpsmux
|
||||
libgstmpegtsdemux
|
||||
libgstmpegtsmux
|
||||
libgstlibav
|
||||
libgstmpg123
|
||||
libgstmusepack
|
||||
libgstogg
|
||||
libgstopenmpt
|
||||
libgstopus
|
||||
libgstopusparse
|
||||
libgstosxaudio
|
||||
libgstpbtypes
|
||||
libgstplayback
|
||||
libgstreplaygain
|
||||
libgstrtp
|
||||
libgstrtsp
|
||||
libgstsoup
|
||||
libgstspectrum
|
||||
libgstspeex
|
||||
libgstspotify
|
||||
libgsttaglib
|
||||
libgsttcp
|
||||
libgsttwolame
|
||||
libgsttypefindfunctions
|
||||
libgstudp
|
||||
libgstvolume
|
||||
libgstvorbis
|
||||
libgstwavenc
|
||||
libgstwavpack
|
||||
libgstwavparse
|
||||
libgstxingmux
|
||||
"
|
||||
|
||||
gst_plugins=$(echo "$gst_plugins" | tr '\n' ' ' | sed -e 's/^ //g' | sed -e 's/ / /g')
|
||||
|
||||
for gst_plugin in $gst_plugins
|
||||
do
|
||||
if [ -f "${GST_PLUGIN_PATH}/${gst_plugin}" ]; then
|
||||
cp -v -f "${GST_PLUGIN_PATH}/${gst_plugin}" "${bundledir}/Contents/PlugIns/gstreamer/" || exit 1
|
||||
for gst_plugin in $gst_plugins; do
|
||||
if [ -e "${GST_PLUGIN_PATH}/${gst_plugin}.dylib" ]; then
|
||||
cp -v -f "${GST_PLUGIN_PATH}/${gst_plugin}.dylib" "${bundledir}/Contents/PlugIns/gstreamer/" || exit 1
|
||||
install_name_tool -id "@rpath/${gst_plugin}.dylib" "${bundledir}/Contents/PlugIns/gstreamer/${gst_plugin}.dylib"
|
||||
elif [ -e "${GST_PLUGIN_PATH}/${gst_plugin}.so" ]; then
|
||||
cp -v -f "${GST_PLUGIN_PATH}/${gst_plugin}.so" "${bundledir}/Contents/PlugIns/gstreamer/" || exit 1
|
||||
install_name_tool -id "@rpath/${gst_plugin}.so" "${bundledir}/Contents/PlugIns/gstreamer/${gst_plugin}.so"
|
||||
else
|
||||
echo "Warning: Missing gstreamer plugin ${GST_PLUGIN_PATH}/${gst_plugin}"
|
||||
echo "Warning: Missing gstreamer plugin ${gst_plugin}."
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -f "/usr/local/lib/libbrotlicommon.1.dylib" ]; then
|
||||
mkdir -p ${bundledir}/Contents/Frameworks
|
||||
cp -v -f "/usr/local/lib/libbrotlicommon.1.dylib" "${bundledir}/Contents/Frameworks/"
|
||||
# libsoup is dynamically loaded by gstreamer, so it needs to be copied.
|
||||
if [ "${LIBSOUP_LIBRARY_PATH}" = "" ]; then
|
||||
echo "Warning: Set the LIBSOUP_LIBRARY_PATH environment variable for copying libsoup."
|
||||
else
|
||||
if [ -e "${LIBSOUP_LIBRARY_PATH}" ]; then
|
||||
mkdir -p "${bundledir}/Contents/Frameworks" || exit 1
|
||||
cp -v -f "${LIBSOUP_LIBRARY_PATH}" "${bundledir}/Contents/Frameworks/" || exit 1
|
||||
install_name_tool -id "@rpath/$(basename ${LIBSOUP_LIBRARY_PATH})" "${bundledir}/Contents/Frameworks/$(basename ${LIBSOUP_LIBRARY_PATH})"
|
||||
else
|
||||
echo "Warning: Missing libsoup ${LIBSOUP_LIBRARY_PATH}."
|
||||
fi
|
||||
fi
|
||||
|
||||
179
dist/scripts/import-from-clementine.sh
vendored
Executable file
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Strawberry Music Player
|
||||
# Copyright 2020, Jonas Kvinge <jonas@jkvinge.net>
|
||||
# 2021 Alexey Vazhnov
|
||||
#
|
||||
# Strawberry is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Strawberry is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
|
||||
# Based on https://github.com/strawberrymusicplayer/strawberry/wiki/Import-collection-library-and-playlists-data-from-Clementine
|
||||
|
||||
set -o nounset
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
shopt -s dotglob
|
||||
|
||||
# Use hardcoded path if no parameters. No need in quotes here! See `man bash`, "Parameter Expansion":
|
||||
FILE_SRC=${1:-~/.config/Clementine/clementine.db}
|
||||
FILE_DST=${2:-~/.local/share/strawberry/strawberry/strawberry.db}
|
||||
|
||||
test -f "$FILE_SRC" || { echo "No such file: $FILE_SRC"; exit 1; }
|
||||
test -f "$FILE_DST" || { echo "No such file: $FILE_DST"; exit 1; }
|
||||
|
||||
echo "Will try to copy information from $FILE_SRC to $FILE_DST."
|
||||
echo
|
||||
echo 'This script will **delete all information** from Strawberry database!'
|
||||
read -r -p 'Do you want to continue? (the only YES is accepted) ' answer
|
||||
if [ "$answer" != "YES" ]; then exit 1; fi
|
||||
|
||||
# 'heredoc' with substitution of variables, see `man bash`, "Here Documents":
|
||||
sqlite3 -batch << EOF
|
||||
.echo on
|
||||
ATTACH '$FILE_DST' AS strawberry;
|
||||
ATTACH '$FILE_SRC' AS clementine;
|
||||
.bail on
|
||||
.databases
|
||||
|
||||
/* This must be done when importing all data from Clementine because playlists are based on ROWIDs */
|
||||
|
||||
DELETE FROM strawberry.directories;
|
||||
DELETE FROM strawberry.subdirectories;
|
||||
DELETE FROM strawberry.songs;
|
||||
DELETE FROM strawberry.playlists;
|
||||
DELETE FROM strawberry.playlist_items;
|
||||
|
||||
/* Import all data from the collection library songs */
|
||||
|
||||
INSERT INTO strawberry.directories (path, subdirs) SELECT path, subdirs FROM clementine.directories;
|
||||
INSERT INTO strawberry.subdirectories (directory_id, path, mtime) SELECT directory, path, mtime FROM clementine.subdirectories;
|
||||
INSERT INTO strawberry.songs (ROWID, title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, beginning, length, bitrate, samplerate, directory_id, url, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, compilation_detected, compilation_on, compilation_off, compilation_effective, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path, rating)
|
||||
SELECT ROWID, title, album, artist, albumartist, track, disc, year, originalyear, genre, compilation, composer, performer, grouping, comment, lyrics, beginning, length, bitrate, samplerate, directory, filename, filetype, filesize, mtime, ctime, unavailable, playcount, skipcount, lastplayed, sampler, forced_compilation_on, forced_compilation_off, effective_compilation, art_automatic, art_manual, effective_albumartist, effective_originalyear, cue_path, rating FROM clementine.songs WHERE unavailable = 0;
|
||||
UPDATE strawberry.songs SET source = 2;
|
||||
UPDATE strawberry.songs SET artist_id = "";
|
||||
UPDATE strawberry.songs SET album_id = "";
|
||||
UPDATE strawberry.songs SET song_id = "";
|
||||
|
||||
/* Import playlists */
|
||||
|
||||
INSERT INTO strawberry.playlists (ROWID, name, last_played, special_type, ui_path, is_favorite, dynamic_playlist_type, dynamic_playlist_data, dynamic_playlist_backend)
|
||||
SELECT ROWID, name, last_played, special_type, ui_path, is_favorite, dynamic_playlist_type, dynamic_playlist_data, dynamic_playlist_backend FROM clementine.playlists WHERE dynamic_playlist_type ISNULL;
|
||||
|
||||
/* Import playlist items */
|
||||
|
||||
INSERT INTO strawberry.playlist_items
|
||||
(ROWID,
|
||||
playlist,
|
||||
collection_id,
|
||||
title,
|
||||
album,
|
||||
artist,
|
||||
albumartist,
|
||||
track,
|
||||
disc,
|
||||
year,
|
||||
originalyear,
|
||||
genre,
|
||||
compilation,
|
||||
composer,
|
||||
performer,
|
||||
grouping,
|
||||
comment,
|
||||
lyrics,
|
||||
beginning,
|
||||
length,
|
||||
bitrate,
|
||||
samplerate,
|
||||
directory_id,
|
||||
url,
|
||||
filetype,
|
||||
filesize,
|
||||
mtime,
|
||||
ctime,
|
||||
unavailable,
|
||||
playcount,
|
||||
skipcount,
|
||||
lastplayed,
|
||||
compilation_detected,
|
||||
compilation_on,
|
||||
compilation_off,
|
||||
compilation_effective,
|
||||
art_automatic,
|
||||
art_manual,
|
||||
effective_albumartist,
|
||||
effective_originalyear,
|
||||
cue_path,
|
||||
rating
|
||||
)
|
||||
SELECT ROWID,
|
||||
playlist,
|
||||
library_id,
|
||||
title,
|
||||
album,
|
||||
artist,
|
||||
albumartist,
|
||||
track,
|
||||
disc,
|
||||
year,
|
||||
originalyear,
|
||||
genre,
|
||||
compilation,
|
||||
composer,
|
||||
performer,
|
||||
grouping,
|
||||
comment,
|
||||
lyrics,
|
||||
beginning,
|
||||
length,
|
||||
bitrate,
|
||||
samplerate,
|
||||
directory,
|
||||
filename,
|
||||
filetype,
|
||||
filesize,
|
||||
mtime,
|
||||
ctime,
|
||||
unavailable,
|
||||
playcount,
|
||||
skipcount,
|
||||
lastplayed,
|
||||
sampler,
|
||||
forced_compilation_on,
|
||||
forced_compilation_off,
|
||||
effective_compilation,
|
||||
art_automatic,
|
||||
art_manual,
|
||||
effective_albumartist,
|
||||
effective_originalyear,
|
||||
cue_path,
|
||||
rating FROM clementine.playlist_items WHERE type = 'Library';
|
||||
|
||||
UPDATE strawberry.playlist_items SET source = 2;
|
||||
UPDATE strawberry.playlist_items SET type = 2;
|
||||
UPDATE strawberry.playlist_items SET artist_id = "";
|
||||
UPDATE strawberry.playlist_items SET album_id = "";
|
||||
UPDATE strawberry.playlist_items SET song_id = "";
|
||||
|
||||
/* Recreate the FTS tables */
|
||||
|
||||
DELETE FROM strawberry.songs_fts;
|
||||
INSERT INTO strawberry.songs_fts (ROWID, ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment)
|
||||
SELECT ROWID, title, album, artist, albumartist, composer, performer, grouping, genre, comment
|
||||
FROM strawberry.songs;
|
||||
|
||||
EOF
|
||||
|
||||
# To be sure script didn't exit because of any error (because we use `set -o errexit`):
|
||||
echo "Script finished"
|
||||
28
dist/scripts/maketarball.sh.in
vendored
@@ -11,10 +11,33 @@ if ! [ "$gitrev" = "ON" ]; then
|
||||
exclude_vcs="--exclude-vcs"
|
||||
fi
|
||||
|
||||
cmds="gtar tar"
|
||||
for cmd in $cmds
|
||||
do
|
||||
which $cmd >/dev/null 2>&1
|
||||
if [ ! $? -eq 0 ]; then
|
||||
continue
|
||||
fi
|
||||
result=$($cmd --version 2>&1 | head -n1)
|
||||
if [ ! $? -eq 0 ]; then
|
||||
continue
|
||||
fi
|
||||
echo "$result" | grep "^.* (GNU tar) .*$" >/dev/null 2>&1
|
||||
if [ ! $? -eq 0 ]; then
|
||||
continue
|
||||
fi
|
||||
TAR=$cmd
|
||||
done
|
||||
|
||||
if [ "$TAR" = "" ]; then
|
||||
echo "ERROR: Missing GNU Tar"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Creating $name-$version.tar.xz..."
|
||||
|
||||
rm -f "$name-$version.tar.xz"
|
||||
tar -cJf $name-$version.tar.xz \
|
||||
${TAR} -cJf $name-$version.tar.xz \
|
||||
--transform "s,^$rootnoslash,$name-$version," $exclude_vcs \
|
||||
--exclude=".directory" \
|
||||
--exclude="*.tar" \
|
||||
@@ -26,6 +49,7 @@ tar -cJf $name-$version.tar.xz \
|
||||
--exclude="*.nsi" \
|
||||
--exclude="*.kdev4" \
|
||||
--exclude=".vscode" \
|
||||
--exclude=".idea" \
|
||||
--exclude="$root/.github" \
|
||||
--exclude="$root/.travis.yml" \
|
||||
--exclude="$root/.circleci" \
|
||||
@@ -33,11 +57,11 @@ tar -cJf $name-$version.tar.xz \
|
||||
--exclude="$root/CMakeLists.txt.user" \
|
||||
--exclude="$root/.clang-format" \
|
||||
--exclude="$root/build" \
|
||||
--exclude="$root/cmake-build-debug" \
|
||||
--exclude="$root/zanata.xml" \
|
||||
--exclude="$root/.zanata-cache" \
|
||||
--exclude="$root/debian/changelog" \
|
||||
--exclude="$root/dist/scripts/maketarball.sh" \
|
||||
--exclude="$root/dist/unix/PKGBUILD" \
|
||||
--exclude="$root/dist/macos/Info.plist" \
|
||||
--exclude="$root/dist/windows/windres.rc" \
|
||||
--exclude="$root/src/translations/translations.pot" \
|
||||
|
||||
56
dist/unix/PKGBUILD.in
vendored
@@ -1,56 +0,0 @@
|
||||
# Maintainer: Jonas Kvinge <jonas@jkvinge.net>
|
||||
pkgname=strawberry
|
||||
pkgver=@STRAWBERRY_VERSION_PAC_V@
|
||||
pkgrel=@STRAWBERRY_VERSION_PAC_R@
|
||||
pkgdesc="A music player aimed at audio enthusiasts and music collectors"
|
||||
arch=(x86_64)
|
||||
url="https://www.strawberrymusicplayer.org/"
|
||||
license=(GPL3)
|
||||
makedepends=(git cmake make gcc boost gettext qt5-tools)
|
||||
depends=(
|
||||
desktop-file-utils
|
||||
hicolor-icon-theme
|
||||
gnutls
|
||||
udisks2
|
||||
protobuf
|
||||
qt5-base
|
||||
qt5-x11extras
|
||||
sqlite3
|
||||
alsa-lib
|
||||
libpulse
|
||||
dbus
|
||||
taglib
|
||||
gstreamer
|
||||
gst-plugins-base
|
||||
gst-plugins-good
|
||||
vlc
|
||||
chromaprint
|
||||
libgpod
|
||||
libcdio
|
||||
libmtp
|
||||
fftw
|
||||
)
|
||||
optdepends=(
|
||||
gst-plugins-bad
|
||||
gst-plugins-ugly
|
||||
gst-libav
|
||||
)
|
||||
provides=(strawberry)
|
||||
conflicts=(strawberry)
|
||||
source=("strawberry-@STRAWBERRY_VERSION_PACKAGE@.tar.xz")
|
||||
sha256sums=('SKIP')
|
||||
|
||||
prepare() {
|
||||
mkdir -p build
|
||||
}
|
||||
|
||||
build() {
|
||||
cd build
|
||||
cmake ../${pkgname}-@STRAWBERRY_VERSION_PACKAGE@ -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd build
|
||||
make DESTDIR="${pkgdir}" install
|
||||
}
|
||||
@@ -1,21 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component>
|
||||
<component type="desktop-application">
|
||||
<id>org.strawberrymusicplayer.strawberry</id>
|
||||
<launchable type="desktop-id">org.strawberrymusicplayer.strawberry.desktop</launchable>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-3.0+</project_license>
|
||||
<provides>
|
||||
<binary>strawberry</binary>
|
||||
<binary>strawberry-tagreader</binary>
|
||||
</provides>
|
||||
<name>Strawberry Music Player</name>
|
||||
<summary>A music player and collection organizer</summary>
|
||||
<url type="homepage">https://www.strawberrymusicplayer.org/</url>
|
||||
<url type="bugtracker">https://github.com/strawberrymusicplayer/strawberry/</url>
|
||||
<developer id="net.jkvinge.jonas">
|
||||
<name>Jonas Kvinge</name>
|
||||
</developer>
|
||||
<translation type="qt">strawberry</translation>
|
||||
<content_rating type="oars-1.1" />
|
||||
<description>
|
||||
<p>
|
||||
Strawberry is a music player and music collection organizer. It is aimed at music collectors and audiophiles. With Strawberry you can play and manage your digital music collection, or stream your favorite radios. It also has unofficial streaming support for Tidal and Qobuz. Strawberry is free software released under GPL. The source code is available on GitHub. It's written in C++ using the Qt toolkit and GStreamer. Strawberry is compatible with both Qt version 5 and 6.
|
||||
Strawberry is a music player and music collection organizer. It is aimed at music collectors and audiophiles. Strawberry is free software released under GPL. It's written in C++ using the Qt framework and GStreamer.
|
||||
</p>
|
||||
<p>Features:</p>
|
||||
<ul>
|
||||
@@ -28,13 +31,12 @@
|
||||
<li>Edit tags on audio files</li>
|
||||
<li>Automatically retrieve tags from MusicBrainz</li>
|
||||
<li>Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify</li>
|
||||
<li>Song lyrics from AudD, Genius, Musixmatch, ChartLyrics, lyrics.ovh and lololyrics.com</li>
|
||||
<li>Support for multiple backends</li>
|
||||
<li>Song lyrics from Genius, Musixmatch, ChartLyrics, lyrics.ovh, lololyrics.com, songlyrics.com, azlyrics.com and elyrics.net</li>
|
||||
<li>Audio analyzer and equalizer</li>
|
||||
<li>Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic</li>
|
||||
<li>Scrobbler with support for Last.fm, Libre.fm and ListenBrainz</li>
|
||||
<li>Streaming support for Subsonic-compatible servers</li>
|
||||
<li>Unofficial streaming support for Tidal and Qobuz</li>
|
||||
<li>Unofficial streaming support for Tidal, Spotify and Qobuz</li>
|
||||
</ul>
|
||||
</description>
|
||||
<screenshots>
|
||||
@@ -48,4 +50,16 @@
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<update_contact>eclipseo@fedoraproject.org</update_contact>
|
||||
<releases>
|
||||
<release version="1.1.3" date="2024-09-21"/>
|
||||
<release version="1.1.2" date="2024-09-12"/>
|
||||
<release version="1.1.1" date="2024-07-22"/>
|
||||
<release version="1.1.0" date="2024-07-14"/>
|
||||
<release version="1.0.23" date="2024-01-11"/>
|
||||
<release version="1.0.22" date="2023-12-09"/>
|
||||
<release version="1.0.21" date="2023-10-21"/>
|
||||
<release version="1.0.20" date="2023-09-24"/>
|
||||
<release version="1.0.19" date="2023-09-24"/>
|
||||
<release version="1.0.18" date="2023-07-02"/>
|
||||
</releases>
|
||||
</component>
|
||||
|
||||
@@ -3,37 +3,43 @@ Version=1.0
|
||||
Type=Application
|
||||
Name=Strawberry
|
||||
GenericName=Strawberry Music Player
|
||||
GenericName[fr]=Lecteur de musique Strawberry
|
||||
GenericName[ru]=Музыкальный проигрыватель Strawberry
|
||||
Comment=Plays music
|
||||
Comment[fr]=Joue de la musique
|
||||
Comment[ru]=Прослушивание музыки
|
||||
Exec=strawberry %U
|
||||
TryExec=strawberry
|
||||
Icon=strawberry
|
||||
Terminal=false
|
||||
Categories=AudioVideo;Player;Qt;Audio;
|
||||
Keywords=Audio;Player;
|
||||
StartupNotify=false
|
||||
MimeType=x-content/audio-player;application/ogg;application/x-ogg;application/x-ogm-audio;audio/flac;audio/ogg;audio/vorbis;audio/aac;audio/mp4;audio/mpeg;audio/mpegurl;audio/vnd.rn-realaudio;audio/x-flac;audio/x-oggflac;audio/x-vorbis;audio/x-vorbis+ogg;audio/x-speex;audio/x-wav;audio/x-wavpack;audio/x-ape;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-ms-wma;audio/x-musepack;audio/x-pn-realaudio;audio/x-scpls;video/x-ms-asf;x-scheme-handler/tidal;
|
||||
StartupWMClass=strawberry
|
||||
Actions=Play;Pause;Stop;StopAfterCurrent;Previous;Next;
|
||||
Actions=Play-Pause;Stop;StopAfterCurrent;Previous;Next;
|
||||
|
||||
[Desktop Action Play]
|
||||
Name=Play
|
||||
Exec=strawberry --play
|
||||
|
||||
[Desktop Action Pause]
|
||||
Name=Pause
|
||||
Exec=strawberry --pause
|
||||
[Desktop Action Play-Pause]
|
||||
Name=Play/Pause
|
||||
Exec=strawberry --play-pause
|
||||
Name[ru]=Играть/пауза
|
||||
|
||||
[Desktop Action Stop]
|
||||
Name=Stop
|
||||
Exec=strawberry --stop
|
||||
Name[ru]=Стоп
|
||||
|
||||
[Desktop Action StopAfterCurrent]
|
||||
Name=Stop after this track
|
||||
Exec=strawberry --stop-after-current
|
||||
Name[ru]=Стоп после этого трека
|
||||
|
||||
[Desktop Action Previous]
|
||||
Name=Previous
|
||||
Exec=strawberry --previous
|
||||
Name[ru]=Предыдущий
|
||||
|
||||
[Desktop Action Next]
|
||||
Name=Next
|
||||
Exec=strawberry --next
|
||||
Name[ru]=Следующий
|
||||
|
||||
10
dist/unix/strawberry-tagreader.1
vendored
@@ -1,10 +0,0 @@
|
||||
.TH STRAWBERRY-TAGREADER "1"
|
||||
.SH NAME
|
||||
strawberry-tagreader \- internal tag reader for strawberry
|
||||
.SH SYNOPSIS
|
||||
.B strawberry-tagreader
|
||||
.SH DESCRIPTION
|
||||
This program is used internally by Strawberry to parse tags in music files without exposing the whole application to crashes caused by malformed files. It is not meant to be run on its own.
|
||||
.SH "AUTHORS"
|
||||
.PP
|
||||
Strawberry main developer is Jonas Kvinge <jonas@jkvinge.net>.
|
||||