mirror of
https://github.com/JosefNemec/Playnite.git
synced 2026-01-09 06:11:22 +08:00
Compare commits
943 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6894a9fd17 | ||
|
|
0ff5138603 | ||
|
|
464bc962a7 | ||
|
|
d57ce71c0a | ||
|
|
775e3152d8 | ||
|
|
f109e48c49 | ||
|
|
05441d38f9 | ||
|
|
bef7cf9597 | ||
|
|
367f2a405d | ||
|
|
abd1d5357f | ||
|
|
4b541c85d6 | ||
|
|
f5062424e8 | ||
|
|
3aeb1516f4 | ||
|
|
7a35bec1ea | ||
|
|
45f7bcb972 | ||
|
|
6480e1cda5 | ||
|
|
3297aeb9e0 | ||
|
|
1e19ce02bd | ||
|
|
81a66b1b0c | ||
|
|
f687ef0cc2 | ||
|
|
5033ede22f | ||
|
|
67f57e1844 | ||
|
|
df654fadb6 | ||
|
|
74de5423ca | ||
|
|
f83c38f7bb | ||
|
|
066d6aa169 | ||
|
|
03bf3ac0a8 | ||
|
|
268522d04e | ||
|
|
c136792790 | ||
|
|
814ddac821 | ||
|
|
c16619337d | ||
|
|
9148d65126 | ||
|
|
c0c2521639 | ||
|
|
0a37c666a7 | ||
|
|
cdc6ccdc39 | ||
|
|
36446d210c | ||
|
|
62768aee71 | ||
|
|
7e2e9da03b | ||
|
|
50f35fc3bf | ||
|
|
77604caf71 | ||
|
|
107cfceb96 | ||
|
|
9cb4d06107 | ||
|
|
ec84070d95 | ||
|
|
16fc7df776 | ||
|
|
7b70f2712f | ||
|
|
ea4f26ac50 | ||
|
|
6816635125 | ||
|
|
b226c08ec0 | ||
|
|
e44dc0df32 | ||
|
|
3ad9d4288f | ||
|
|
699dedf5f3 | ||
|
|
16942a6073 | ||
|
|
ed20d6d2dc | ||
|
|
a44fa41a8c | ||
|
|
94bf35fa3d | ||
|
|
dde38e4136 | ||
|
|
4d5fb929d5 | ||
|
|
42022a2093 | ||
|
|
f1cbbc418d | ||
|
|
c00445a33e | ||
|
|
6ff11c2bf5 | ||
|
|
50728257d3 | ||
|
|
f32afd1087 | ||
|
|
1d8d1f1a2a | ||
|
|
417b88901a | ||
|
|
05f9d2a2cb | ||
|
|
76d93543e0 | ||
|
|
35ca484ff7 | ||
|
|
74aad5d714 | ||
|
|
07b96f4d7d | ||
|
|
3245d76dd0 | ||
|
|
a5cb7135d6 | ||
|
|
2ca5c57408 | ||
|
|
1bd8ade1f0 | ||
|
|
9f82f71463 | ||
|
|
b3020edbac | ||
|
|
8dc6f1572f | ||
|
|
c405080b27 | ||
|
|
3300269ea1 | ||
|
|
641f45b4af | ||
|
|
77cc78733a | ||
|
|
83320df7df | ||
|
|
82029ca907 | ||
|
|
cc4dc68ba3 | ||
|
|
4594621aa5 | ||
|
|
4f83fc8f5d | ||
|
|
c0b82391fe | ||
|
|
891b63bd0f | ||
|
|
09f65c765a | ||
|
|
fd3f981270 | ||
|
|
7508794f6f | ||
|
|
a1720895cc | ||
|
|
9a9eadc419 | ||
|
|
bdebf009f3 | ||
|
|
36a9439b37 | ||
|
|
31225440c1 | ||
|
|
049fcc4526 | ||
|
|
70f7ae0408 | ||
|
|
954f166cf7 | ||
|
|
9aa99451d0 | ||
|
|
653bd46810 | ||
|
|
0cf6193ef1 | ||
|
|
c265fb02d6 | ||
|
|
eb4a6593e2 | ||
|
|
8ee01d3cf7 | ||
|
|
043cd6937b | ||
|
|
38024ad644 | ||
|
|
32cd48ec7e | ||
|
|
1545c67f99 | ||
|
|
e27cd6e52f | ||
|
|
1286e81c43 | ||
|
|
38804bdc2f | ||
|
|
ac5246ea78 | ||
|
|
b10a4f9df6 | ||
|
|
ff2fa7258a | ||
|
|
546a750b28 | ||
|
|
ff4c748600 | ||
|
|
fb41277253 | ||
|
|
9655e9766d | ||
|
|
a9eb258b54 | ||
|
|
acec5ff30c | ||
|
|
ee569b1217 | ||
|
|
274d3dcc18 | ||
|
|
efd6ca3043 | ||
|
|
a8264d3a0f | ||
|
|
22c699d647 | ||
|
|
5a09e924c5 | ||
|
|
e1db07f59c | ||
|
|
76bca4b756 | ||
|
|
726bfee156 | ||
|
|
1805473f60 | ||
|
|
d8a8e38276 | ||
|
|
f97b68475c | ||
|
|
02e55e1e30 | ||
|
|
a53ea74af3 | ||
|
|
a5acdf38a9 | ||
|
|
485c5292b1 | ||
|
|
b840a34f5d | ||
|
|
0d6ecf6e0a | ||
|
|
75372a6d70 | ||
|
|
ce0caeaa33 | ||
|
|
8e54aca7ed | ||
|
|
8d1a3c11a9 | ||
|
|
cf9c3fae82 | ||
|
|
961100a36f | ||
|
|
fba7c5c83a | ||
|
|
8f5eb2c167 | ||
|
|
f0ed21cb9d | ||
|
|
05edfc21d7 | ||
|
|
fdb2a8652a | ||
|
|
2afc8359d8 | ||
|
|
a821d10dbc | ||
|
|
5e5786f6c8 | ||
|
|
4efc2fb6c4 | ||
|
|
665aad0ccd | ||
|
|
5dfb0b1dd9 | ||
|
|
caa6ca6951 | ||
|
|
0e73be1b05 | ||
|
|
aaadf99cfe | ||
|
|
79e19cc5f6 | ||
|
|
e6e8b36cb3 | ||
|
|
df52f03d3d | ||
|
|
5d78389514 | ||
|
|
07110f9779 | ||
|
|
a0ef9331c5 | ||
|
|
0d4a992708 | ||
|
|
01521d4f84 | ||
|
|
c222d51953 | ||
|
|
bd47f60b01 | ||
|
|
8c5a747819 | ||
|
|
9f58828fd8 | ||
|
|
ef9effdd27 | ||
|
|
642ce6fc4c | ||
|
|
06d6314b9b | ||
|
|
aba112c06a | ||
|
|
413a65be71 | ||
|
|
2c34720ad5 | ||
|
|
d1b69409b4 | ||
|
|
9f02a8dd93 | ||
|
|
ea276512f2 | ||
|
|
ef0a2d88d8 | ||
|
|
836137d1da | ||
|
|
c5ba48b097 | ||
|
|
b97d78d3e3 | ||
|
|
c92ac029cf | ||
|
|
9bd0f7e523 | ||
|
|
99046fb49f | ||
|
|
a617a5786d | ||
|
|
96f6221448 | ||
|
|
6b7ab24e76 | ||
|
|
fe46a55e5f | ||
|
|
836c18cb26 | ||
|
|
5e383291db | ||
|
|
bf68c8cc64 | ||
|
|
21f9e3efd2 | ||
|
|
676a2bc3c1 | ||
|
|
5cdd1a2d3e | ||
|
|
6859e9dd89 | ||
|
|
40b72eacc0 | ||
|
|
deb2ce3598 | ||
|
|
1951654f68 | ||
|
|
e7b478af8d | ||
|
|
e4c8cf95a6 | ||
|
|
750e19441a | ||
|
|
8680e53c2c | ||
|
|
8109ad325f | ||
|
|
0a19c614aa | ||
|
|
4a1ccbb4f8 | ||
|
|
b14d643b87 | ||
|
|
790b6b1d8c | ||
|
|
edb556bdca | ||
|
|
4c03306ff4 | ||
|
|
1c2897f2dd | ||
|
|
0ea205ece5 | ||
|
|
0d1c06dafc | ||
|
|
215d4492f1 | ||
|
|
502331175b | ||
|
|
e4369f31aa | ||
|
|
00d4887f2b | ||
|
|
3adefef807 | ||
|
|
9437dbf34d | ||
|
|
ade485bfa9 | ||
|
|
42e3a894a1 | ||
|
|
5d92080d32 | ||
|
|
de76a5ee00 | ||
|
|
5d0440e41b | ||
|
|
d3e540a4e5 | ||
|
|
2d08a74bbf | ||
|
|
5b60061b08 | ||
|
|
eb006a3ee2 | ||
|
|
34f5c569bb | ||
|
|
0a022e4587 | ||
|
|
ede248e0ab | ||
|
|
bea776f6d2 | ||
|
|
85d15baf6f | ||
|
|
d6c74a5bcf | ||
|
|
b1e1ade3d9 | ||
|
|
b47d8ce76c | ||
|
|
0471ceb97a | ||
|
|
9b60abf8f2 | ||
|
|
d1634e849b | ||
|
|
642cb3f6fb | ||
|
|
431abb4ee5 | ||
|
|
d41e29a5a2 | ||
|
|
9067546916 | ||
|
|
ec46359e7a | ||
|
|
4ec4e4256c | ||
|
|
1d205595e7 | ||
|
|
fa46d0408c | ||
|
|
2427d80ce1 | ||
|
|
048fd3ad26 | ||
|
|
a0b8002b34 | ||
|
|
3bc56e650e | ||
|
|
13198290a0 | ||
|
|
2b32cb4236 | ||
|
|
d5ceb576b1 | ||
|
|
465bf27047 | ||
|
|
2dd7c41c16 | ||
|
|
9d19b25fac | ||
|
|
d3068730a8 | ||
|
|
fd9e160746 | ||
|
|
e24f93827c | ||
|
|
39e7ff0569 | ||
|
|
ee15d63efd | ||
|
|
653c110709 | ||
|
|
21b666a3a1 | ||
|
|
26b8e1f9a7 | ||
|
|
d34ab58f7a | ||
|
|
8834be12f9 | ||
|
|
344719c82f | ||
|
|
d2b1870512 | ||
|
|
e693a935f3 | ||
|
|
7ef242812b | ||
|
|
33a49edf02 | ||
|
|
84bc65f39e | ||
|
|
6db9b61cfa | ||
|
|
377fcb9b75 | ||
|
|
e168f8cead | ||
|
|
49dbca774e | ||
|
|
d2d3a03168 | ||
|
|
96d246c4ac | ||
|
|
005f02dc6f | ||
|
|
673a38d1f8 | ||
|
|
07c71e611e | ||
|
|
0c85acbf61 | ||
|
|
a2ca4e0da4 | ||
|
|
89dd631c29 | ||
|
|
37e29f28a0 | ||
|
|
dada5264b2 | ||
|
|
71e93a9630 | ||
|
|
490f8208e8 | ||
|
|
53450b6fb1 | ||
|
|
a3030925a9 | ||
|
|
7e2dfa7fda | ||
|
|
3bda573777 | ||
|
|
16273c943b | ||
|
|
297f5a770c | ||
|
|
58fe736c16 | ||
|
|
0f8c104b88 | ||
|
|
55cee73946 | ||
|
|
fa2a28c977 | ||
|
|
a8e10ee316 | ||
|
|
75ddd43ff1 | ||
|
|
b124418eb9 | ||
|
|
6ed93b4ffd | ||
|
|
3f48a96484 | ||
|
|
9ef99bb9e0 | ||
|
|
1a14c9e44f | ||
|
|
966d3c45fc | ||
|
|
4e67e7e6a7 | ||
|
|
946b542c85 | ||
|
|
e4101472d4 | ||
|
|
bd16943ab3 | ||
|
|
ce888b456f | ||
|
|
41e7440f71 | ||
|
|
2cda95ed85 | ||
|
|
21f836767b | ||
|
|
2d8da1c48d | ||
|
|
a60a72e3fe | ||
|
|
7ce8fb09e3 | ||
|
|
313839f987 | ||
|
|
985a939127 | ||
|
|
d6314395cb | ||
|
|
196d4f9777 | ||
|
|
c745a76160 | ||
|
|
97ee0ffd3d | ||
|
|
16a6e4c197 | ||
|
|
dd466bbd0f | ||
|
|
998623a257 | ||
|
|
14aa930c04 | ||
|
|
081bbd3329 | ||
|
|
8f9a0a5256 | ||
|
|
10a8f8dc14 | ||
|
|
6444da103d | ||
|
|
851979f718 | ||
|
|
af2696d6ff | ||
|
|
dd138fb6d3 | ||
|
|
712f3e136d | ||
|
|
6e480a181a | ||
|
|
ab7976db22 | ||
|
|
1efe594562 | ||
|
|
e5862b1f34 | ||
|
|
7f7919e001 | ||
|
|
d73c5fecb6 | ||
|
|
0525b492c2 | ||
|
|
5fbc2358e6 | ||
|
|
d4877fb105 | ||
|
|
b6b695962d | ||
|
|
d286723721 | ||
|
|
01ed24134d | ||
|
|
a275dd2882 | ||
|
|
128a7733cc | ||
|
|
2abbb3b3c0 | ||
|
|
43a747b64d | ||
|
|
0d9cd61838 | ||
|
|
16df9569c6 | ||
|
|
f263ec6f0f | ||
|
|
7037e9869b | ||
|
|
e637ff1e53 | ||
|
|
84a7675d3e | ||
|
|
5c2934f7ef | ||
|
|
4c27649f27 | ||
|
|
25694585b8 | ||
|
|
733f451bbb | ||
|
|
63222f8824 | ||
|
|
decf7ab36c | ||
|
|
16d9b27ca7 | ||
|
|
49f696e30b | ||
|
|
a3d1788a29 | ||
|
|
4f41dbd52c | ||
|
|
4546b781da | ||
|
|
aa05b62f99 | ||
|
|
f40422782e | ||
|
|
e2aac0a4a4 | ||
|
|
cef3868da1 | ||
|
|
1baf5e8a30 | ||
|
|
250aa96b8f | ||
|
|
b92d96cb24 | ||
|
|
e1ad7fd011 | ||
|
|
54488a22fa | ||
|
|
78be2d3024 | ||
|
|
88bba7eece | ||
|
|
aa64aacb14 | ||
|
|
b758f08dd9 | ||
|
|
7c22b85a69 | ||
|
|
b49bbd4f3b | ||
|
|
dff379c663 | ||
|
|
2cf5df86e2 | ||
|
|
eb05b57fbb | ||
|
|
0ec7741227 | ||
|
|
73243de216 | ||
|
|
3483d4f4d1 | ||
|
|
e94d36dfd8 | ||
|
|
90e758d104 | ||
|
|
1ea3518a15 | ||
|
|
caf001609e | ||
|
|
86c432b697 | ||
|
|
d291ce27ac | ||
|
|
766d355a83 | ||
|
|
14d51bc351 | ||
|
|
efdf643166 | ||
|
|
6280520b31 | ||
|
|
4f515c566e | ||
|
|
4df1c2c981 | ||
|
|
e97e0251ea | ||
|
|
3db3d4a01a | ||
|
|
48f398b4bd | ||
|
|
ef8d5f1cd6 | ||
|
|
91918b7aca | ||
|
|
4525b3977d | ||
|
|
68414e9b34 | ||
|
|
910e4f26d8 | ||
|
|
5bd51dfeeb | ||
|
|
c1a3c272d9 | ||
|
|
60200a826a | ||
|
|
a5c71e1284 | ||
|
|
07fdf8b018 | ||
|
|
d1df302efb | ||
|
|
c28edfa482 | ||
|
|
7b48a16fe9 | ||
|
|
dda57636eb | ||
|
|
50b91154c8 | ||
|
|
b4eeff8fc4 | ||
|
|
1dcbdb36d1 | ||
|
|
74278dd14f | ||
|
|
56d6707b7f | ||
|
|
1784d2cb10 | ||
|
|
979ed6e693 | ||
|
|
9ed6cf38fb | ||
|
|
a592653dc9 | ||
|
|
5560d4a096 | ||
|
|
3e0ed361ad | ||
|
|
f6e01a7304 | ||
|
|
a7e74cd1c2 | ||
|
|
d3ded3b6ae | ||
|
|
937cd39148 | ||
|
|
b5db5537f4 | ||
|
|
9c3008fad1 | ||
|
|
9857cb4741 | ||
|
|
5e53c31906 | ||
|
|
61371f92a2 | ||
|
|
eab8ba6b28 | ||
|
|
ba48df9613 | ||
|
|
af95d5c286 | ||
|
|
e08635337f | ||
|
|
6b87389d1a | ||
|
|
d72bb108e3 | ||
|
|
8e67105c93 | ||
|
|
133dc5f119 | ||
|
|
a47fcdc59a | ||
|
|
bb53c96615 | ||
|
|
5970336718 | ||
|
|
2ab29a7f30 | ||
|
|
1d164769a0 | ||
|
|
1bfa8e8506 | ||
|
|
c6c978cfad | ||
|
|
8c6843c2fd | ||
|
|
950f9fc713 | ||
|
|
c68a9b4dc1 | ||
|
|
d96f1b8a16 | ||
|
|
82470d2f6d | ||
|
|
69b625acfc | ||
|
|
31c5e3136d | ||
|
|
27a366890b | ||
|
|
3ed242333f | ||
|
|
1994d001eb | ||
|
|
7842423a35 | ||
|
|
e118cbd381 | ||
|
|
1d4025f4b9 | ||
|
|
20efd93196 | ||
|
|
cca64425be | ||
|
|
6a77c85b35 | ||
|
|
6d18d14995 | ||
|
|
d12fd019a5 | ||
|
|
fcf39062ca | ||
|
|
fa40a5fabb | ||
|
|
bd7d433d78 | ||
|
|
e02fd37308 | ||
|
|
764c2b0a53 | ||
|
|
61b56f780c | ||
|
|
72fae4ba24 | ||
|
|
815a63e3db | ||
|
|
db32dcfc16 | ||
|
|
6b446151f1 | ||
|
|
d53ceffec7 | ||
|
|
27f3b20e38 | ||
|
|
5206a37939 | ||
|
|
fecdf56731 | ||
|
|
8a50df4916 | ||
|
|
066c12b776 | ||
|
|
9f27b70738 | ||
|
|
01d0b37e37 | ||
|
|
dbb637062c | ||
|
|
617f995032 | ||
|
|
fe3c0db2d4 | ||
|
|
3ea431d893 | ||
|
|
ab4f0ba761 | ||
|
|
716d711103 | ||
|
|
9f524fcc3b | ||
|
|
6c203e34a2 | ||
|
|
469ea22896 | ||
|
|
7273751a23 | ||
|
|
151eb08387 | ||
|
|
b446685527 | ||
|
|
58094b3766 | ||
|
|
4a26add24f | ||
|
|
71f091b763 | ||
|
|
f217c76b56 | ||
|
|
89c0f48feb | ||
|
|
dc3e8f3313 | ||
|
|
d6967bc159 | ||
|
|
703e3bab13 | ||
|
|
350b359fc5 | ||
|
|
c1d58a94b3 | ||
|
|
268f3acd12 | ||
|
|
356d3858e3 | ||
|
|
90de50ec24 | ||
|
|
019dc14900 | ||
|
|
18ce695e20 | ||
|
|
df96760f4c | ||
|
|
7adba8f42e | ||
|
|
1ab72765b5 | ||
|
|
e013fd22f2 | ||
|
|
273a0c1d3e | ||
|
|
0bf33a87ab | ||
|
|
3c04ac6d38 | ||
|
|
d540d67d27 | ||
|
|
971d462cbb | ||
|
|
cde8c992b4 | ||
|
|
8ad1266613 | ||
|
|
c127b10077 | ||
|
|
d27e5cfb03 | ||
|
|
847c26ac93 | ||
|
|
5b7f670116 | ||
|
|
5cbd03f8fb | ||
|
|
b784905ea9 | ||
|
|
66663f2f9b | ||
|
|
fd6cbb6b5c | ||
|
|
752a174219 | ||
|
|
837a12b0bc | ||
|
|
3bc01f3935 | ||
|
|
4d79098f31 | ||
|
|
758331aa6a | ||
|
|
30aa952b7f | ||
|
|
0ca9176b09 | ||
|
|
d95ececa0a | ||
|
|
c648418b77 | ||
|
|
a06812339b | ||
|
|
54b882e4cc | ||
|
|
a2107dc4e7 | ||
|
|
9c7b79ffda | ||
|
|
1386f5abdd | ||
|
|
a5ff8162ab | ||
|
|
4acaa7eaa8 | ||
|
|
f92814b45c | ||
|
|
b4357a2f37 | ||
|
|
6aac3674f5 | ||
|
|
ce834146ff | ||
|
|
f37b278beb | ||
|
|
cc1b75f269 | ||
|
|
f879806984 | ||
|
|
207a4ac699 | ||
|
|
18312ce69b | ||
|
|
818f67515c | ||
|
|
2137b5839c | ||
|
|
3dcfe90f7a | ||
|
|
5b0ac6698a | ||
|
|
eea978caa4 | ||
|
|
444fb1333b | ||
|
|
cbbe47eac8 | ||
|
|
43249ad8d3 | ||
|
|
3565ff6a5f | ||
|
|
21a5ab4f0a | ||
|
|
b08d5f2028 | ||
|
|
ed9e5f0f93 | ||
|
|
cbffb408d8 | ||
|
|
7d78293e0e | ||
|
|
1ed6ad1317 | ||
|
|
a8ab171fb9 | ||
|
|
9596ca51de | ||
|
|
1573ff95e6 | ||
|
|
fcc3636f5c | ||
|
|
e9e9be7d4e | ||
|
|
d6b3f52ae3 | ||
|
|
47115bbd6e | ||
|
|
732cff18f0 | ||
|
|
da96e9ce44 | ||
|
|
ac10c7a701 | ||
|
|
2cff60f31b | ||
|
|
68a0f9bf4d | ||
|
|
b25c25a136 | ||
|
|
15d5b5b2af | ||
|
|
087f65677d | ||
|
|
8197dfc201 | ||
|
|
08b2274890 | ||
|
|
c8b650286c | ||
|
|
c21203a93d | ||
|
|
b3f31b0b84 | ||
|
|
773217b579 | ||
|
|
c9c59d039e | ||
|
|
e67ba59baf | ||
|
|
5224edbd35 | ||
|
|
61286e0eeb | ||
|
|
25e1a5b4a1 | ||
|
|
8cc0a8d267 | ||
|
|
4f8ffb0278 | ||
|
|
220480ff7a | ||
|
|
c41c5194fe | ||
|
|
f1f8c844d3 | ||
|
|
ade8c682cd | ||
|
|
1b0e6209d4 | ||
|
|
a1268d191f | ||
|
|
76ed9c0152 | ||
|
|
15ebf28f05 | ||
|
|
2fb2c98c68 | ||
|
|
66d71f6ed0 | ||
|
|
89208035bc | ||
|
|
b8b76e6584 | ||
|
|
b17555e3a2 | ||
|
|
ae57d8a284 | ||
|
|
34ad611fb1 | ||
|
|
7e0e2148e1 | ||
|
|
3d9a5d64d4 | ||
|
|
bbeaffd195 | ||
|
|
f6545534d1 | ||
|
|
5ffc66cf87 | ||
|
|
4904831783 | ||
|
|
dafaad9a61 | ||
|
|
eeef95804c | ||
|
|
4e17416f86 | ||
|
|
b48e5872f2 | ||
|
|
23c1b5456a | ||
|
|
d8c0cfa68a | ||
|
|
f9d6b2208e | ||
|
|
468725179f | ||
|
|
2a4412c6d6 | ||
|
|
823e3f1442 | ||
|
|
a03ffbc65e | ||
|
|
86194038e8 | ||
|
|
4982133062 | ||
|
|
c24966d211 | ||
|
|
18edc9aa65 | ||
|
|
62112bb4d5 | ||
|
|
bd3a4a125f | ||
|
|
f0b0039989 | ||
|
|
56f6f0f54b | ||
|
|
8976d7a3d6 | ||
|
|
4c73fa2ac5 | ||
|
|
ffdfbdfcf0 | ||
|
|
c5962da43d | ||
|
|
f2418eb7ca | ||
|
|
8e19a94c80 | ||
|
|
5a53d97816 | ||
|
|
4630dbbcab | ||
|
|
007261dd71 | ||
|
|
9119a70233 | ||
|
|
709a48adc2 | ||
|
|
dfb7375d3c | ||
|
|
d5a716b27e | ||
|
|
f1326ae995 | ||
|
|
c8b8c7e47d | ||
|
|
df622595df | ||
|
|
7350fba5f7 | ||
|
|
346db4bd57 | ||
|
|
7afd1afe50 | ||
|
|
1bd1adf606 | ||
|
|
11e6c8ff0c | ||
|
|
69d44436d4 | ||
|
|
4b4b061b56 | ||
|
|
d9acdc249e | ||
|
|
89ff94b8a4 | ||
|
|
3ad410738d | ||
|
|
9afd846369 | ||
|
|
6dc213ef1f | ||
|
|
50e90b49a8 | ||
|
|
42f34ee8f1 | ||
|
|
e3bf7c1f1e | ||
|
|
3a4c04abdd | ||
|
|
56d09a4a29 | ||
|
|
fe0b7af137 | ||
|
|
2d78f3e637 | ||
|
|
e0de8c1dce | ||
|
|
a7094ad550 | ||
|
|
46a403af6a | ||
|
|
52f87a589d | ||
|
|
6b760441bd | ||
|
|
1815f6b1eb | ||
|
|
512b816bc5 | ||
|
|
b85221fef4 | ||
|
|
76282796f2 | ||
|
|
659a7e4780 | ||
|
|
e390aad518 | ||
|
|
21b51226c7 | ||
|
|
f31d75386b | ||
|
|
8339c02fd0 | ||
|
|
adc6846a8d | ||
|
|
9c414df219 | ||
|
|
2c7fa9455e | ||
|
|
e666fed4b7 | ||
|
|
1989c5e035 | ||
|
|
c7e7df5ab0 | ||
|
|
1fdbdf1746 | ||
|
|
13367e3f4f | ||
|
|
4394293e8c | ||
|
|
440769047d | ||
|
|
0684bc563a | ||
|
|
80d526c896 | ||
|
|
d73c886f1b | ||
|
|
cb99606805 | ||
|
|
11c5c311a2 | ||
|
|
9ead1e94a4 | ||
|
|
188cb57964 | ||
|
|
f532e4933a | ||
|
|
d33a96a595 | ||
|
|
f1a0755b63 | ||
|
|
106fc48114 | ||
|
|
4e82a31d56 | ||
|
|
95ba4fad16 | ||
|
|
d94a2555c9 | ||
|
|
e6367eb61d | ||
|
|
a690eef012 | ||
|
|
8f4e34f7da | ||
|
|
c31ceddf6f | ||
|
|
50a28feea7 | ||
|
|
eb7433e993 | ||
|
|
98fe3740ed | ||
|
|
285d2bbeaf | ||
|
|
9f7086698a | ||
|
|
8db6599e16 | ||
|
|
6f0ca4b654 | ||
|
|
207fbd39a7 | ||
|
|
0f5538cb32 | ||
|
|
29d3d0cde9 | ||
|
|
55f642f802 | ||
|
|
8275bda346 | ||
|
|
a8b0aa0034 | ||
|
|
bd07350136 | ||
|
|
8cc176bc83 | ||
|
|
23b4d96b2d | ||
|
|
1ba76f3d77 | ||
|
|
70940ed52e | ||
|
|
a4495dcc41 | ||
|
|
7c6c11497e | ||
|
|
a4ace08da0 | ||
|
|
42bfd94c5e | ||
|
|
ceb69b0e58 | ||
|
|
77352deb0b | ||
|
|
308dfce73d | ||
|
|
1e996a0877 | ||
|
|
07f9eb8114 | ||
|
|
8bafed434c | ||
|
|
3cb88a26e9 | ||
|
|
ebef613735 | ||
|
|
5549a86c37 | ||
|
|
5901a83512 | ||
|
|
c17018f17b | ||
|
|
8087fc3a3d | ||
|
|
e4b66a0b2d | ||
|
|
e7460cb47e | ||
|
|
14da669c64 | ||
|
|
f5c42ce133 | ||
|
|
a296279ca9 | ||
|
|
dc115b0509 | ||
|
|
9a331db707 | ||
|
|
6ddf09e52e | ||
|
|
1f8be488c0 | ||
|
|
4a6fe7144e | ||
|
|
90f855cd7a | ||
|
|
b515bd62dc | ||
|
|
1ff4d7b80d | ||
|
|
e73af0b0a3 | ||
|
|
69b039d132 | ||
|
|
f03f113c34 | ||
|
|
93c776513a | ||
|
|
77139db532 | ||
|
|
6d68174f42 | ||
|
|
c9ad3a3b28 | ||
|
|
248d0a7439 | ||
|
|
2b0d4a4732 | ||
|
|
9f38af9d2f | ||
|
|
dcbed19fcf | ||
|
|
a6b6caa1d5 | ||
|
|
1bfc74d8f9 | ||
|
|
95d4aab90a | ||
|
|
572e2363da | ||
|
|
e9e85d0789 | ||
|
|
d4eaf11cde | ||
|
|
ad33cf6a31 | ||
|
|
31602a43fe | ||
|
|
9d66fa2056 | ||
|
|
0aa89af583 | ||
|
|
0024a78b59 | ||
|
|
165f35dc2b | ||
|
|
8c4f763163 | ||
|
|
e71d605693 | ||
|
|
0051721dfb | ||
|
|
7d022f490a | ||
|
|
87a8dfff81 | ||
|
|
8ad0f5647d | ||
|
|
6e7d3b043f | ||
|
|
eb19fcb579 | ||
|
|
81bfa113d5 | ||
|
|
ed9edd305a | ||
|
|
a77f8c3e5f | ||
|
|
f83d555683 | ||
|
|
877480bbf2 | ||
|
|
8583eede87 | ||
|
|
6831b351d5 | ||
|
|
a564e2c9fa | ||
|
|
0bbb056ff8 | ||
|
|
189b005689 | ||
|
|
c060288502 | ||
|
|
b0250bd764 | ||
|
|
6d108e3fd6 | ||
|
|
90e099601a | ||
|
|
77fdd28c9a | ||
|
|
2b53707d36 | ||
|
|
85ce9267a1 | ||
|
|
460906990c | ||
|
|
67c8958f46 | ||
|
|
b098aca69f | ||
|
|
73e7a95ab1 | ||
|
|
b857d57348 | ||
|
|
1a761e90b8 | ||
|
|
7be345a286 | ||
|
|
5ca6f0c428 | ||
|
|
d015e44b90 | ||
|
|
8fb8ca4bcf | ||
|
|
f9e23b8d73 | ||
|
|
2e911e99c7 | ||
|
|
fd4397f5f6 | ||
|
|
1722e16892 | ||
|
|
0554b725d1 | ||
|
|
35727c405a | ||
|
|
6eeff82211 | ||
|
|
0878dae889 | ||
|
|
d41a6a2ff7 | ||
|
|
8a0b231362 | ||
|
|
442007ae66 | ||
|
|
cde8de80af | ||
|
|
42e331c57d | ||
|
|
d2f46970f0 | ||
|
|
4a8efd6ba4 | ||
|
|
34b06255cc | ||
|
|
3e378ae28d | ||
|
|
9077258e1b | ||
|
|
73fb67b1f3 | ||
|
|
9a1424a076 | ||
|
|
044518ee53 | ||
|
|
d209e07bfe | ||
|
|
72aedcc758 | ||
|
|
ce1dbe28cc | ||
|
|
ff13c8c3e9 | ||
|
|
67ded8f8cb | ||
|
|
a416f22c0b | ||
|
|
f2f8bd69ab | ||
|
|
4b99faf902 | ||
|
|
56f7ec13dc | ||
|
|
8301e60cc1 | ||
|
|
f098292de9 | ||
|
|
741572c373 | ||
|
|
1ff77d0618 | ||
|
|
4b2e44622a | ||
|
|
6331beb7b2 | ||
|
|
1ee2b711f8 | ||
|
|
dbf5723470 | ||
|
|
571b8f93d5 | ||
|
|
015d3203fe | ||
|
|
61dc95df16 | ||
|
|
aa93a0c7c1 | ||
|
|
4c955d50fb | ||
|
|
1de9d49ad3 | ||
|
|
950be21db0 | ||
|
|
52e7140ea2 | ||
|
|
3daa4b01f0 | ||
|
|
20ff365bf0 | ||
|
|
00bb9440e1 | ||
|
|
a89475b5f1 | ||
|
|
b243ccc8ec | ||
|
|
eabadf617b | ||
|
|
0b22eeeed3 | ||
|
|
85ec0a5529 | ||
|
|
ae832a90b8 | ||
|
|
e402d81301 | ||
|
|
1529482cee | ||
|
|
d5e0472d76 | ||
|
|
b44a515f58 | ||
|
|
bd8c75078a | ||
|
|
5ef02ad277 | ||
|
|
9c3dd524d0 | ||
|
|
9377328cd6 | ||
|
|
ae3c14bfab | ||
|
|
bd8e2c5bc3 | ||
|
|
d59ab132bd | ||
|
|
ebdd6ca8ff | ||
|
|
4743a55d8f | ||
|
|
4fd8ad68c4 | ||
|
|
b5889eb123 | ||
|
|
d7a40c8a97 | ||
|
|
0b0f3c38bd | ||
|
|
c320280911 | ||
|
|
9596f6a5fb | ||
|
|
4cf021d998 | ||
|
|
c270700e69 | ||
|
|
02328aa2db | ||
|
|
58bb31a265 | ||
|
|
23117b130f | ||
|
|
e881643b8d | ||
|
|
3e8b6222e1 | ||
|
|
47e5c2f849 | ||
|
|
5a0d41cb21 | ||
|
|
deda98f223 | ||
|
|
5544b34716 | ||
|
|
49cbcd6aa3 | ||
|
|
d08dcc0440 | ||
|
|
253b47630e | ||
|
|
e579dd8b33 | ||
|
|
ca585cbad2 | ||
|
|
9cb4df4571 | ||
|
|
aed07c4ed1 | ||
|
|
c11ebbf2d4 | ||
|
|
e5f5ed64d4 | ||
|
|
49dec948b6 | ||
|
|
585617c3e9 | ||
|
|
77270a29f2 | ||
|
|
48877c8bad | ||
|
|
cb0ff5a111 | ||
|
|
78b120a959 | ||
|
|
d65fd2cd50 | ||
|
|
a43dfa0a47 | ||
|
|
e662a4c61c | ||
|
|
445d3b0058 | ||
|
|
6e209dad21 | ||
|
|
cb79d854d3 | ||
|
|
35fb47caa9 | ||
|
|
1c9d59e16f | ||
|
|
2887537efe | ||
|
|
4b9efd9e6b | ||
|
|
b582ed7022 | ||
|
|
7dc72cfd8a | ||
|
|
b2e3cd443f | ||
|
|
b3b9119048 | ||
|
|
0c563827a5 |
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@ -1,3 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
patreon: playnite
|
||||
ko_fi: playnite
|
||||
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,28 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Before creating bug report**
|
||||
- Please use issue search in the repository first. If the bug is something really obvious there's a high change it was already reported.
|
||||
- Make sure that the issue is not caused by custom theme or extension. You can restart Playnite in "safe mode" from help menu to quickly test it.
|
||||
- Check list of known issues https://github.com/JosefNemec/Playnite/wiki/Known-Issues
|
||||
|
||||
**Integration issues**
|
||||
If an issue is related to library integrations, use separate [extensions repository](https://github.com/JosefNemec/PlayniteExtensions) to file a report.
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
If it's not clear from the description how to reproduce the issue please add clear steps to reproduce the behavior.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Diagnostics ID**
|
||||
Please generate diagnostics package from "About Playnite" menu and attach identifier you received. If the issue is a crash bug, you can generate diag. package directly from crash dialog.
|
||||
39
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
39
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
name: Bug report
|
||||
description: Create a report to help us improve
|
||||
labels: ['bug']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**Before creating bug report:**
|
||||
- Please post in English language only!
|
||||
- Please use issue search in the repository first. If the bug is something really obvious there's a high change it was already reported.
|
||||
- Make sure that the issue is not caused by custom theme or extension. You can restart Playnite in "safe mode" from help menu to quickly test it.
|
||||
- Check list of known issues https://github.com/JosefNemec/Playnite/wiki/Known-Issues
|
||||
|
||||
**Integration issues**
|
||||
If an issue is related to library integrations, use separate [extensions repository](https://github.com/JosefNemec/PlayniteExtensions) to file a report.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Bug Description
|
||||
description: A clear and concise description of what the bug is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: To Reproduce
|
||||
description: If it''s not clear from the description how to reproduce the issue please add clear steps to reproduce the behavior.
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
attributes:
|
||||
label: Diagnostics ID
|
||||
description: 'Please generate diagnostics package from "About Playnite" menu and attach identifier you received. If the issue is a crash bug, you can generate diag. package directly from crash dialog.'
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If applicable, add screenshots to help explain your problem.
|
||||
validations:
|
||||
required: false
|
||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,8 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Playnite Discord server
|
||||
url: https://discord.gg/BrtABqe
|
||||
url: https://playnite.link/discord
|
||||
about: Official Discord server for general chat and support with Playnite.
|
||||
- name: Playnite SDK documentation
|
||||
url: https://playnite.link/docs/
|
||||
about: Useful documentation when creating pluings and themes.
|
||||
about: Useful documentation when creating plugins and themes.
|
||||
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Integration features**
|
||||
If a feature request is related to library integrations, use separate [extensions repository](https://github.com/JosefNemec/PlayniteExtensions) to file a request.
|
||||
|
||||
**Check for existing issue**
|
||||
Please use issue search in the repository if your feature request is something really obvious there's a high change it was already requested.
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain requested changes.
|
||||
26
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
26
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
name: Feature request
|
||||
description: Suggest an idea for this project
|
||||
labels: ['enhancement']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please post in English language only!
|
||||
|
||||
**Integration features**
|
||||
If a feature request is related to library integrations, use separate [extensions repository](https://github.com/JosefNemec/PlayniteExtensions) to file a request.
|
||||
|
||||
**Check for existing issue**
|
||||
Please use issue search in the repository if your feature request is something really obvious there's a high change it was already requested.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Feature description
|
||||
description: A clear and concise description of feature you want to be added.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If applicable, add screenshots to help explain requested changes.
|
||||
validations:
|
||||
required: false
|
||||
7
.github/pull_request_template.md
vendored
7
.github/pull_request_template.md
vendored
@ -1,4 +1,3 @@
|
||||
I have verified that:
|
||||
- [ ] These changes work, by building the application and testing them.
|
||||
- [ ] Pull request is targeting `devel` branch.
|
||||
- [ ] I added myself into [contributors file](https://github.com/JosefNemec/Playnite/blob/devel/source/Playnite.DesktopApp/Resources/contributors.txt) if I want to receive contribution credit in the application itself.
|
||||
Pull requests are generally on pause because majority of code base is being rewritten for Playnite 11.
|
||||
|
||||
Smaller "safe" changes for P10 might get accepted based on what they and if they come with test coverage. If you plan to work on bigger changes, please discuss it first in related issue or on Discord, thank you.
|
||||
|
||||
70
README.md
70
README.md
@ -1,6 +1,6 @@
|
||||
|
||||
# <img src="https://playnite.link/applogo.png" width="32"> Playnite [](https://crowdin.com/project/playnite)
|
||||
An open source video game library manager and launcher with support for 3rd party libraries like Steam, GOG, Origin, Battle.net and Uplay. Includes game emulation support, providing one unified interface for your games.
|
||||
An open source video game library manager and launcher with support for 3rd party libraries like Steam, Epic, GOG, EA App, Battle.net and [others](https://playnite.link/addons.html). Includes game emulation support, providing one unified interface for your games.
|
||||
|
||||
Screenshots are available at the [Homepage](http://playnite.link/)
|
||||
|
||||
@ -16,43 +16,44 @@ Download
|
||||
|
||||
Grab the latest installer or portable package from the [download](https://playnite.link/download.html) page. Playnite will automatically notify you about a new version upon release.
|
||||
|
||||
Requirements: Windows 7, 8 or 10 and [.NET Framework 4.6.2](https://www.microsoft.com/en-us/download/details.aspx?id=53344)
|
||||
Requirements: Windows 10 or 11
|
||||
|
||||
Extensions
|
||||
FAQ, Known Issues, user manual
|
||||
---------
|
||||
Playnite can be extended with plugins (written in .NET languages) or by scripts (PowerShell and IronPython are currently supported).
|
||||
|
||||
See the [extensions portal](https://playnite.link/docs/) for tutorials and the full API documentation.
|
||||
|
||||
FAQ
|
||||
---------
|
||||
Can be found [on the wiki](https://github.com/JosefNemec/Playnite/wiki/Frequently-Asked-Questions)
|
||||
|
||||
Known Issues
|
||||
---------
|
||||
The list of known issues and solutions can be found [on the wiki](https://github.com/JosefNemec/Playnite/wiki/Known-Issues).
|
||||
|
||||
Privacy Statement
|
||||
---------
|
||||
Playnite doesn't store any user information and you don't need to provide any information to import installed games. Account connection process is usually done via official login web forms and only the web session cookies or tokens are stored, the same way when you login to those services via the web browser.
|
||||
|
||||
All information about your library is stored locally on your PC.
|
||||
Can be found [here](https://api.playnite.link/docs/)
|
||||
|
||||
Questions, issues etc.
|
||||
---------
|
||||
If you find a bug please file an [issue](https://github.com/JosefNemec/Playnite/issues) and if relevant (crashes, broken features) please attach a diagnostics package, which can be created from inside the "About Playnite..." submenu.
|
||||
|
||||
Biggest community around Playnite currently gathers on our [Discord server](https://discord.gg/hSFvmN6) and [Forums](https://playnite.link/forum). You can also follow [@AppPlaynite](https://twitter.com/AppPlaynite) for general updates.
|
||||
Biggest community around Playnite currently gathers on our [Discord server](https://playnite.link/discord) and [Reddit](https://www.reddit.com/r/playnite/).
|
||||
|
||||
Contributions
|
||||
Privacy Statement
|
||||
---------
|
||||
### Translations
|
||||
See the [How to: Translations](https://github.com/JosefNemec/Playnite/wiki/How-to:-Translations) wiki page.
|
||||
Playnite itself doesn't store any user information and you generally don't need to provide any information to import installed games. All game library data is stored locally on your PC.
|
||||
|
||||
### Themes
|
||||
See the [How to: Themes](https://github.com/JosefNemec/Playnite/wiki/How-to%3A-Themes) wiki page.
|
||||
Account connection process depends on how a library plugin is implemented, but is usually done via official login web forms and only the web session cookies or tokens are stored, the same way when you login to those services via the web browser.
|
||||
|
||||
Add-ons
|
||||
---------
|
||||
Playnite can be extended with plugins (written in .NET languages), PowerShell scripts and user interface themes.
|
||||
|
||||
See the [extensions portal](https://api.playnite.link/docs/tutorials/index.html) for more information about how to make these addons.
|
||||
|
||||
Translations
|
||||
---------
|
||||
|
||||
We use Crowdin to manage localization, please join our project if you want to submit translations:
|
||||
|
||||
https://crowdin.com/project/playnite
|
||||
|
||||
Proofreading changes to original English strings can be submitted by creating pull request for [LocSource.xaml](https://github.com/JosefNemec/Playnite/blob/devel/source/Playnite/Localization/LocSource.xaml) file.
|
||||
|
||||
Code Contributions
|
||||
---------
|
||||
|
||||
Pull requests are generally on pause because majority of code base is being rewritten for Playnite 11. Smaller "safe" changes for P10 might get accepted based on what they and if they come with test coverage. If you plan to work on bigger changes, please discuss it first in related issue or on Discord, thank you.
|
||||
|
||||
### Code Contributions
|
||||
Please ask in the related issue first before starting implementing something to make sure that nobody else is already working on it. If an issue doesn't exist for your feature/bug fix, create one first.
|
||||
|
||||
Regarding code styling, there are only a few major rules:
|
||||
@ -60,20 +61,24 @@ Regarding code styling, there are only a few major rules:
|
||||
- private fields and properties should use camelCase (without underscore)
|
||||
- all methods (private and public) should use PascalCase
|
||||
- use spaces instead of tabs with 4 spaces width
|
||||
- add empty line between code block end `}` and additional expression
|
||||
- always encapsulate the code body after *if, for, foreach, while* etc. with curly braces:
|
||||
|
||||
```csharp
|
||||
if (true)
|
||||
{
|
||||
DoSomething()
|
||||
DoSomething();
|
||||
}
|
||||
|
||||
DoSomethingElse();
|
||||
```
|
||||
|
||||
instead of
|
||||
|
||||
```csharp
|
||||
if (true)
|
||||
DoSomething()
|
||||
DoSomething();
|
||||
DoSomethingElse();
|
||||
```
|
||||
|
||||
Branches
|
||||
@ -85,7 +90,7 @@ Branches
|
||||
Roadmap
|
||||
---------
|
||||
|
||||
You can see the planned versions with their features in the [milestones overview](https://github.com/JosefNemec/Playnite/milestones).
|
||||
Playnite is currently being rewritten from scratch for next major version release 11. The work is being done in private repository until beta release, after which the code will be release in this repository under the same license as current version 10 release. There is no list of planned changes and new features for version 11.
|
||||
|
||||
Development
|
||||
---------
|
||||
@ -99,7 +104,6 @@ Others
|
||||
|
||||
[](https://www.jetbrains.com/?from=Playnite)
|
||||
|
||||
Code signing courtesy of [SignPath](https://about.signpath.io)
|
||||
|
||||
[](https://about.signpath.io)
|
||||
This program uses free code signing provided by [SignPath.io](https://signpath.io?utm_source=foundation&utm_medium=github&utm_campaign=playnite), and a free code signing certificate by the [SignPath Foundation](https://signpath.org?utm_source=foundation&utm_medium=github&utm_campaign=playnite)
|
||||
|
||||
[](https://about.signpath.io?utm_source=foundation&utm_medium=github&utm_campaign=playnite)
|
||||
|
||||
@ -1,36 +1,330 @@
|
||||
Playnite.SDK.dll
|
||||
Playnite.SDK.pdb
|
||||
Playnite.SDK.xml
|
||||
Playnite.Common.dll
|
||||
Playnite.Common.pdb
|
||||
LiteDB.dll
|
||||
LiteDB.xml
|
||||
Newtonsoft.Json.dll
|
||||
Newtonsoft.Json.xml
|
||||
System.IO.Abstractions.dll
|
||||
System.IO.Abstractions.xml
|
||||
NLog.dll
|
||||
NLog.xml
|
||||
Windows.winmd
|
||||
AngleSharp.dll
|
||||
AngleSharp.xml
|
||||
YamlDotNet.dll
|
||||
YamlDotNet.xml
|
||||
Nett.dll
|
||||
Nett.xml
|
||||
Microsoft.WindowsAPICodePack.dll
|
||||
Microsoft.WindowsAPICodePack.Shell.dll
|
||||
SQLNado.dll
|
||||
Markdig.dll
|
||||
Markdig.xml
|
||||
Markdig.pdb
|
||||
NAudio.dll
|
||||
NAudio.xml
|
||||
CefSharp.dll
|
||||
CefSharp.BrowserSubprocess.Core.dll
|
||||
CefSharp.Core.dll
|
||||
CefSharp.Core.Runtime.dll
|
||||
CefSharp.OffScreen.dll
|
||||
CefSharp.Wpf.dll
|
||||
CommandLine.dll
|
||||
concrt140.dll
|
||||
Crc32.NET.dll
|
||||
Crc32.NET.xml
|
||||
d3dcompiler_47.dll
|
||||
DiscordRPC.dll
|
||||
Flurl.dll
|
||||
Flurl.xml
|
||||
Hardcodet.Wpf.TaskbarNotification.dll
|
||||
HtmlRenderer.dll
|
||||
HtmlRenderer.xml
|
||||
HtmlRenderer.WPF.dll
|
||||
HtmlRenderer.WPF.xml
|
||||
chrome_elf.dll
|
||||
libcef.dll
|
||||
libEGL.dll
|
||||
libGLESv2.dll
|
||||
LiteDB.dll
|
||||
Magick.Native-Q8-x86.dll
|
||||
Magick.NET.Core.dll
|
||||
Magick.NET.SystemWindowsMedia.dll
|
||||
Magick.NET-Q8-x86.dll
|
||||
Markdig.dll
|
||||
Microsoft.Dynamic.dll
|
||||
Microsoft.Practices.ServiceLocation.dll
|
||||
Microsoft.Scripting.dll
|
||||
Microsoft.Scripting.Metadata.dll
|
||||
Microsoft.VisualStudio.CodeCoverage.Shim.dll
|
||||
Microsoft.Win32.Primitives.dll
|
||||
Microsoft.WindowsAPICodePack.dll
|
||||
Microsoft.WindowsAPICodePack.ExtendedLinguisticServices.dll
|
||||
Microsoft.WindowsAPICodePack.Sensors.dll
|
||||
Microsoft.WindowsAPICodePack.Shell.dll
|
||||
Microsoft.WindowsAPICodePack.ShellExtensions.dll
|
||||
Microsoft.Xaml.Behaviors.dll
|
||||
msvcp140.dll
|
||||
msvcp140_1.dll
|
||||
msvcp140_2.dll
|
||||
msvcp140_atomic_wait.dll
|
||||
msvcp140_codecvt_ids.dll
|
||||
netstandard.dll
|
||||
Nett.dll
|
||||
Newtonsoft.Json.dll
|
||||
NLog.dll
|
||||
PhotoSauce.MagicScaler.dll
|
||||
Playnite.dll
|
||||
Playnite.SDK.dll
|
||||
Polly.dll
|
||||
Prism.dll
|
||||
Prism.Wpf.dll
|
||||
protobuf-net.dll
|
||||
SDL2.dll
|
||||
SDL2_mixer.dll
|
||||
SharpCompress.dll
|
||||
sqlite3.x86.dll
|
||||
SQLNado.dll
|
||||
System.AppContext.dll
|
||||
System.Buffers.dll
|
||||
System.Collections.dll
|
||||
System.Collections.Concurrent.dll
|
||||
System.Collections.NonGeneric.dll
|
||||
System.Collections.Specialized.dll
|
||||
System.ComponentModel.dll
|
||||
System.ComponentModel.EventBasedAsync.dll
|
||||
System.ComponentModel.Primitives.dll
|
||||
System.ComponentModel.TypeConverter.dll
|
||||
System.Console.dll
|
||||
System.Data.Common.dll
|
||||
System.Diagnostics.Contracts.dll
|
||||
System.Diagnostics.Debug.dll
|
||||
System.Diagnostics.FileVersionInfo.dll
|
||||
System.Diagnostics.Process.dll
|
||||
System.Diagnostics.StackTrace.dll
|
||||
System.Diagnostics.TextWriterTraceListener.dll
|
||||
System.Diagnostics.Tools.dll
|
||||
System.Diagnostics.TraceSource.dll
|
||||
System.Diagnostics.Tracing.dll
|
||||
System.Drawing.Primitives.dll
|
||||
System.Dynamic.Runtime.dll
|
||||
System.Globalization.dll
|
||||
System.Globalization.Calendars.dll
|
||||
System.Globalization.Extensions.dll
|
||||
System.IO.dll
|
||||
System.IO.Abstractions.dll
|
||||
System.IO.Compression.dll
|
||||
System.IO.Compression.ZipFile.dll
|
||||
System.IO.FileSystem.dll
|
||||
System.IO.FileSystem.DriveInfo.dll
|
||||
System.IO.FileSystem.Primitives.dll
|
||||
System.IO.FileSystem.Watcher.dll
|
||||
System.IO.IsolatedStorage.dll
|
||||
System.IO.MemoryMappedFiles.dll
|
||||
System.IO.Pipes.dll
|
||||
System.IO.UnmanagedMemoryStream.dll
|
||||
System.Linq.dll
|
||||
System.Linq.Expressions.dll
|
||||
System.Linq.Parallel.dll
|
||||
System.Linq.Queryable.dll
|
||||
System.Memory.dll
|
||||
System.Net.Http.dll
|
||||
System.Net.NameResolution.dll
|
||||
System.Net.NetworkInformation.dll
|
||||
System.Net.Ping.dll
|
||||
System.Net.Primitives.dll
|
||||
System.Net.Requests.dll
|
||||
System.Net.Security.dll
|
||||
System.Net.Sockets.dll
|
||||
System.Net.WebHeaderCollection.dll
|
||||
System.Net.WebSockets.dll
|
||||
System.Net.WebSockets.Client.dll
|
||||
System.Numerics.Vectors.dll
|
||||
System.ObjectModel.dll
|
||||
System.Reflection.dll
|
||||
System.Reflection.Extensions.dll
|
||||
System.Reflection.Primitives.dll
|
||||
System.Resources.Reader.dll
|
||||
System.Resources.ResourceManager.dll
|
||||
System.Resources.Writer.dll
|
||||
System.Runtime.dll
|
||||
System.Runtime.CompilerServices.Unsafe.dll
|
||||
System.Runtime.CompilerServices.VisualC.dll
|
||||
System.Runtime.Extensions.dll
|
||||
System.Runtime.Handles.dll
|
||||
System.Runtime.InteropServices.dll
|
||||
System.Runtime.InteropServices.RuntimeInformation.dll
|
||||
System.Runtime.Numerics.dll
|
||||
System.Runtime.Serialization.Formatters.dll
|
||||
System.Runtime.Serialization.Json.dll
|
||||
System.Runtime.Serialization.Primitives.dll
|
||||
System.Runtime.Serialization.Xml.dll
|
||||
System.Security.Claims.dll
|
||||
System.Security.Cryptography.Algorithms.dll
|
||||
System.Security.Cryptography.Csp.dll
|
||||
System.Security.Cryptography.Encoding.dll
|
||||
System.Security.Cryptography.Primitives.dll
|
||||
System.Security.Cryptography.X509Certificates.dll
|
||||
System.Security.Principal.dll
|
||||
System.Security.SecureString.dll
|
||||
System.Text.Encoding.dll
|
||||
System.Text.Encoding.Extensions.dll
|
||||
System.Text.RegularExpressions.dll
|
||||
System.Threading.dll
|
||||
System.Threading.Overlapped.dll
|
||||
System.Threading.Tasks.dll
|
||||
System.Threading.Tasks.Parallel.dll
|
||||
System.Threading.Thread.dll
|
||||
System.Threading.ThreadPool.dll
|
||||
System.Threading.Timer.dll
|
||||
System.ValueTuple.dll
|
||||
System.Windows.Interactivity.dll
|
||||
System.Xml.ReaderWriter.dll
|
||||
System.Xml.XDocument.dll
|
||||
System.Xml.XmlDocument.dll
|
||||
System.Xml.XmlSerializer.dll
|
||||
System.Xml.XPath.dll
|
||||
System.Xml.XPath.XDocument.dll
|
||||
vccorlib140.dll
|
||||
vcruntime140.dll
|
||||
vcruntime140_threads.dll
|
||||
vk_swiftshader.dll
|
||||
vulkan-1.dll
|
||||
YamlDotNet.dll
|
||||
AngleSharp.xml
|
||||
CefSharp.xml
|
||||
CefSharp.BrowserSubprocess.Core.xml
|
||||
CefSharp.Core.xml
|
||||
CefSharp.Core.Runtime.xml
|
||||
CefSharp.OffScreen.xml
|
||||
CefSharp.Wpf.xml
|
||||
CommandLine.xml
|
||||
concrt140.xml
|
||||
Crc32.NET.xml
|
||||
d3dcompiler_47.xml
|
||||
DiscordRPC.xml
|
||||
Flurl.xml
|
||||
Hardcodet.Wpf.TaskbarNotification.xml
|
||||
HtmlRenderer.xml
|
||||
HtmlRenderer.WPF.xml
|
||||
chrome_elf.xml
|
||||
libcef.xml
|
||||
libEGL.xml
|
||||
libGLESv2.xml
|
||||
LiteDB.xml
|
||||
Magick.Native-Q8-x86.xml
|
||||
Magick.NET.Core.xml
|
||||
Magick.NET.SystemWindowsMedia.xml
|
||||
Magick.NET-Q8-x86.xml
|
||||
Markdig.xml
|
||||
Microsoft.Dynamic.xml
|
||||
Microsoft.Practices.ServiceLocation.xml
|
||||
Microsoft.Scripting.xml
|
||||
Microsoft.Scripting.Metadata.xml
|
||||
Microsoft.VisualStudio.CodeCoverage.Shim.xml
|
||||
Microsoft.Win32.Primitives.xml
|
||||
Microsoft.WindowsAPICodePack.xml
|
||||
Microsoft.WindowsAPICodePack.ExtendedLinguisticServices.xml
|
||||
Microsoft.WindowsAPICodePack.Sensors.xml
|
||||
Microsoft.WindowsAPICodePack.Shell.xml
|
||||
Microsoft.WindowsAPICodePack.ShellExtensions.xml
|
||||
Microsoft.Xaml.Behaviors.xml
|
||||
msvcp140.xml
|
||||
msvcp140_1.xml
|
||||
msvcp140_2.xml
|
||||
msvcp140_atomic_wait.xml
|
||||
msvcp140_codecvt_ids.xml
|
||||
netstandard.xml
|
||||
Nett.xml
|
||||
Newtonsoft.Json.xml
|
||||
NLog.xml
|
||||
PhotoSauce.MagicScaler.xml
|
||||
Playnite.xml
|
||||
Playnite.SDK.xml
|
||||
Polly.xml
|
||||
Prism.xml
|
||||
Prism.Wpf.xml
|
||||
protobuf-net.xml
|
||||
SDL2.xml
|
||||
SDL2_mixer.xml
|
||||
SharpCompress.xml
|
||||
sqlite3.x86.xml
|
||||
SQLNado.xml
|
||||
System.AppContext.xml
|
||||
System.Buffers.xml
|
||||
System.Collections.xml
|
||||
System.Collections.Concurrent.xml
|
||||
System.Collections.NonGeneric.xml
|
||||
System.Collections.Specialized.xml
|
||||
System.ComponentModel.xml
|
||||
System.ComponentModel.EventBasedAsync.xml
|
||||
System.ComponentModel.Primitives.xml
|
||||
System.ComponentModel.TypeConverter.xml
|
||||
System.Console.xml
|
||||
System.Data.Common.xml
|
||||
System.Diagnostics.Contracts.xml
|
||||
System.Diagnostics.Debug.xml
|
||||
System.Diagnostics.FileVersionInfo.xml
|
||||
System.Diagnostics.Process.xml
|
||||
System.Diagnostics.StackTrace.xml
|
||||
System.Diagnostics.TextWriterTraceListener.xml
|
||||
System.Diagnostics.Tools.xml
|
||||
System.Diagnostics.TraceSource.xml
|
||||
System.Diagnostics.Tracing.xml
|
||||
System.Drawing.Primitives.xml
|
||||
System.Dynamic.Runtime.xml
|
||||
System.Globalization.xml
|
||||
System.Globalization.Calendars.xml
|
||||
System.Globalization.Extensions.xml
|
||||
System.IO.xml
|
||||
System.IO.Abstractions.xml
|
||||
System.IO.Compression.xml
|
||||
System.IO.Compression.ZipFile.xml
|
||||
System.IO.FileSystem.xml
|
||||
System.IO.FileSystem.DriveInfo.xml
|
||||
System.IO.FileSystem.Primitives.xml
|
||||
System.IO.FileSystem.Watcher.xml
|
||||
System.IO.IsolatedStorage.xml
|
||||
System.IO.MemoryMappedFiles.xml
|
||||
System.IO.Pipes.xml
|
||||
System.IO.UnmanagedMemoryStream.xml
|
||||
System.Linq.xml
|
||||
System.Linq.Expressions.xml
|
||||
System.Linq.Parallel.xml
|
||||
System.Linq.Queryable.xml
|
||||
System.Memory.xml
|
||||
System.Net.Http.xml
|
||||
System.Net.NameResolution.xml
|
||||
System.Net.NetworkInformation.xml
|
||||
System.Net.Ping.xml
|
||||
System.Net.Primitives.xml
|
||||
System.Net.Requests.xml
|
||||
System.Net.Security.xml
|
||||
System.Net.Sockets.xml
|
||||
System.Net.WebHeaderCollection.xml
|
||||
System.Net.WebSockets.xml
|
||||
System.Net.WebSockets.Client.xml
|
||||
System.Numerics.Vectors.xml
|
||||
System.ObjectModel.xml
|
||||
System.Reflection.xml
|
||||
System.Reflection.Extensions.xml
|
||||
System.Reflection.Primitives.xml
|
||||
System.Resources.Reader.xml
|
||||
System.Resources.ResourceManager.xml
|
||||
System.Resources.Writer.xml
|
||||
System.Runtime.xml
|
||||
System.Runtime.CompilerServices.Unsafe.xml
|
||||
System.Runtime.CompilerServices.VisualC.xml
|
||||
System.Runtime.Extensions.xml
|
||||
System.Runtime.Handles.xml
|
||||
System.Runtime.InteropServices.xml
|
||||
System.Runtime.InteropServices.RuntimeInformation.xml
|
||||
System.Runtime.Numerics.xml
|
||||
System.Runtime.Serialization.Formatters.xml
|
||||
System.Runtime.Serialization.Json.xml
|
||||
System.Runtime.Serialization.Primitives.xml
|
||||
System.Runtime.Serialization.Xml.xml
|
||||
System.Security.Claims.xml
|
||||
System.Security.Cryptography.Algorithms.xml
|
||||
System.Security.Cryptography.Csp.xml
|
||||
System.Security.Cryptography.Encoding.xml
|
||||
System.Security.Cryptography.Primitives.xml
|
||||
System.Security.Cryptography.X509Certificates.xml
|
||||
System.Security.Principal.xml
|
||||
System.Security.SecureString.xml
|
||||
System.Text.Encoding.xml
|
||||
System.Text.Encoding.Extensions.xml
|
||||
System.Text.RegularExpressions.xml
|
||||
System.Threading.xml
|
||||
System.Threading.Overlapped.xml
|
||||
System.Threading.Tasks.xml
|
||||
System.Threading.Tasks.Parallel.xml
|
||||
System.Threading.Thread.xml
|
||||
System.Threading.ThreadPool.xml
|
||||
System.Threading.Timer.xml
|
||||
System.ValueTuple.xml
|
||||
System.Windows.Interactivity.xml
|
||||
System.Xml.ReaderWriter.xml
|
||||
System.Xml.XDocument.xml
|
||||
System.Xml.XmlDocument.xml
|
||||
System.Xml.XmlSerializer.xml
|
||||
System.Xml.XPath.xml
|
||||
System.Xml.XPath.XDocument.xml
|
||||
vccorlib140.xml
|
||||
vcruntime140.xml
|
||||
vcruntime140_threads.xml
|
||||
vk_swiftshader.xml
|
||||
vulkan-1.xml
|
||||
YamlDotNet.xml
|
||||
@ -17,10 +17,12 @@
|
||||
<dependencies>
|
||||
<group targetFramework=".NETFramework4.6.2" />
|
||||
</dependencies>
|
||||
<readme>docs\readme.md</readme>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="{OutDir}\Playnite.SDK.dll" target="lib\net462\Playnite.SDK.dll" />
|
||||
<file src="{OutDir}\Playnite.SDK.xml" target="lib\net462\Playnite.SDK.xml" />
|
||||
<file src="..\source\Playnite.DesktopApp\Themes\Desktop\Default\Images\applogo.png" target="images\" />
|
||||
<file src="..\source\PlayniteSDK\readme.md" target="docs\" />
|
||||
</files>
|
||||
</package>
|
||||
@ -1,3 +1,5 @@
|
||||
#Requires -Version 7
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
Add-Type -AssemblyName "PresentationFramework"
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#Requires -Version 7
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
Add-Type -AssemblyName "PresentationFramework"
|
||||
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
param(
|
||||
#Requires -Version 7
|
||||
|
||||
param(
|
||||
# Build configuration
|
||||
[ValidateSet("Release", "Debug")]
|
||||
[string]$Configuration = "Release",
|
||||
@ -121,7 +123,7 @@ if (!$SkipBuild)
|
||||
{
|
||||
if (Test-Path $OutputDir)
|
||||
{
|
||||
Remove-Item $OutputDir -Recurse -Force
|
||||
Remove-Item "$OutputDir\*" -Recurse -Force
|
||||
}
|
||||
|
||||
if ($LicensedDependenciesUrl)
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
param(
|
||||
[switch]$SkipMetadata
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
& .\common.ps1
|
||||
|
||||
if (!$SkipMetadata)
|
||||
{
|
||||
$metadata = StartAndWait "docfx" "metadata" "..\doc\"
|
||||
if ($metadata -ne 0)
|
||||
{
|
||||
throw "Failed to build doc metadata."
|
||||
}
|
||||
}
|
||||
|
||||
$build = StartAndWait "docfx" "build" "..\doc\"
|
||||
if ($build -ne 0)
|
||||
{
|
||||
throw "Failed to build doc."
|
||||
}
|
||||
@ -1,3 +1,5 @@
|
||||
#Requires -Version 7
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
& .\common.ps1
|
||||
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
param(
|
||||
#Requires -Version 7
|
||||
|
||||
param(
|
||||
[ValidateSet("Release", "Debug")]
|
||||
[string]$Configuration = "Release",
|
||||
[string]$OutputPath = (Join-Path $PWD "$($Configuration)SDK"),
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
$global:NugetUrl = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
|
||||
#Requires -Version 7
|
||||
|
||||
$global:NugetUrl = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
|
||||
|
||||
function global:StartAndWait()
|
||||
{
|
||||
@ -53,20 +55,14 @@ function global:Get-MsBuildPath()
|
||||
|
||||
if (-not (Get-Command -Name $VSWHERE_CMD -Type Application -ErrorAction Ignore))
|
||||
{
|
||||
$VSWHERE_CMD = "..\source\packages\vswhere.2.6.7\tools\vswhere.exe"
|
||||
$VSWHERE_CMD = "..\source\packages\vswhere.*\tools\vswhere.exe"
|
||||
if (-not (Get-Command -Name $VSWHERE_CMD -Type Application -ErrorAction Ignore))
|
||||
{
|
||||
Invoke-Nuget "install vswhere -Version 2.6.7 -SolutionDirectory `"$solutionDir`"" | Out-Null
|
||||
Invoke-Nuget "install vswhere -SolutionDirectory `"$solutionDir`"" | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
$path = & $VSWHERE_CMD -version "[15.0,16.0)" -requires Microsoft.Component.MSBuild -find "MSBuild\**\Bin\MSBuild.exe" -latest | Select-Object -First 1
|
||||
if ($path -and (Test-Path $path))
|
||||
{
|
||||
return $path
|
||||
}
|
||||
|
||||
$path = & $VSWHERE_CMD -version "[16.0,17.0)" -requires Microsoft.Component.MSBuild -find "MSBuild\**\Bin\MSBuild.exe" -latest | Select-Object -First 1
|
||||
$path = & $VSWHERE_CMD -latest -requires Microsoft.Component.MSBuild -find "MSBuild\**\Bin\MSBuild.exe" -latest | Select-Object -First 1
|
||||
if ($path -and (Test-Path $path))
|
||||
{
|
||||
return $path
|
||||
|
||||
487
build/generateRetroArchProfile.ps1
Normal file
487
build/generateRetroArchProfile.ps1
Normal file
@ -0,0 +1,487 @@
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$RetroArchDir,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$PlayniteSourceDirectory
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
if (!(Get-InstalledModule "powershell-yaml" -EA 0))
|
||||
{
|
||||
Install-Module powershell-yaml
|
||||
}
|
||||
|
||||
function Get-IsYamlValid
|
||||
{
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $yamlContent
|
||||
)
|
||||
|
||||
try {
|
||||
$yamlContent | ConvertFrom-Yaml | Out-Null
|
||||
return $true
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function ParseInfoFile()
|
||||
{
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
$properties = @{}
|
||||
foreach ($line in (Get-Content $Path))
|
||||
{
|
||||
if ($line.StartsWith("#"))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if ($line -match "^(.*)\s*=\s*`"(.*)`"$")
|
||||
{
|
||||
$property = $Matches[1].Trim()
|
||||
if (!$properties.ContainsKey($property))
|
||||
{
|
||||
$properties.Add($property, $Matches[2].Trim())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $properties
|
||||
}
|
||||
|
||||
$emulationDirPath = [System.IO.Path]::Combine($PlayniteSourceDirectory, "Playnite", "Emulation")
|
||||
$platformsDefinitionPath = [System.IO.Path]::Combine($emulationDirPath, "Platforms.yaml")
|
||||
$retroArchEmuDefinitionPath = [System.IO.Path]::Combine($emulationDirPath, "Emulators", "RetroArch", "emulator.yaml")
|
||||
|
||||
if (!(Test-Path $platformsDefinitionPath -Type Leaf))
|
||||
{
|
||||
Write-Host "Playnite platforms definition file not found in $platformsDefinitionPath" -ForegroundColor Yellow
|
||||
return
|
||||
}
|
||||
|
||||
$ignoreList = @(
|
||||
"00_example_libretro.info",
|
||||
"2048_libretro.info",
|
||||
"3dengine_libretro.info",
|
||||
"advanced_tests_libretro.info",
|
||||
"bk_libretro.info",
|
||||
"boom3_libretro.info",
|
||||
"boom3_xp_libretro.info",
|
||||
"cannonball_libretro.info",
|
||||
"chaigame_libretro.info",
|
||||
"chailove_libretro.info",
|
||||
"craft_libretro.info",
|
||||
"cruzes_libretro.info",
|
||||
"dhewm3_libretro.info",
|
||||
"dinothawr_libretro.info",
|
||||
"ecwolf_libretro.info",
|
||||
"ffmpeg_libretro.info",
|
||||
"freechaf_libretro.info",
|
||||
"freej2me_libretro.info",
|
||||
"gme_libretro.info",
|
||||
"hbmame_libretro.info",
|
||||
"imageviewer_libretro.info",
|
||||
"lutro_libretro.info",
|
||||
"mojozork_libretro.info",
|
||||
"mpv_libretro.info",
|
||||
"mrboom_libretro.info",
|
||||
"mu_libretro.info",
|
||||
"nxengine_libretro.info",
|
||||
"oberon_libretro.info",
|
||||
"openlara_libretro.info",
|
||||
"opentyrian_libretro.info",
|
||||
"pascal_pong_libretro.info",
|
||||
"pocketcdg_libretro.info",
|
||||
"pokemini_libretro.info",
|
||||
"prboom_libretro.info",
|
||||
"quasi88_libretro.info",
|
||||
"redbook_libretro.info",
|
||||
"reminiscence_libretro.info",
|
||||
"remotejoy_libretro.info",
|
||||
"rvvm_libretro.info",
|
||||
"scummvm_libretro.info",
|
||||
"simcp_libretro.info",
|
||||
"squirreljme_libretro.info",
|
||||
"stonesoup_libretro.info",
|
||||
"test_libretro.info",
|
||||
"test_netplay_libretro.info",
|
||||
"testaudio_callback_libretro.info",
|
||||
"testaudio_no_callback_libretro.info",
|
||||
"testaudio_playback_wav_libretro.info",
|
||||
"testgl_compute_shaders_libretro.info",
|
||||
"testgl_ff_libretro.info",
|
||||
"testgl_libretro.info",
|
||||
"testinput_buttontest_libretro.info",
|
||||
"testretroluxury_libretro.info",
|
||||
"testsw_libretro.info",
|
||||
"testsw_vram_libretro.info",
|
||||
"testvulkan_async_compute_libretro.info",
|
||||
"testvulkan_libretro.info",
|
||||
"thepowdertoy_libretro.info",
|
||||
"tic80_libretro.info",
|
||||
"tyrquake_libretro.info",
|
||||
"ume2015_libretro.info",
|
||||
"uw8_libretro.info",
|
||||
"vaporspec_libretro.info",
|
||||
"vitaquake2-rogue_libretro.info",
|
||||
"vitaquake2-xatrix_libretro.info",
|
||||
"vitaquake2-zaero_libretro.info",
|
||||
"vitaquake2_libretro.info",
|
||||
"vitaquake3_libretro.info",
|
||||
"vitavoyager_libretro.info",
|
||||
"wasm4_libretro.info",
|
||||
"x1_libretro.info",
|
||||
"xrick_libretro.info"
|
||||
)
|
||||
|
||||
$retroarchArcadeSystems = @(
|
||||
"16-bit (Various)",
|
||||
"16-bit + 32X (Various)",
|
||||
"Arcade (various)",
|
||||
"CP System I",
|
||||
"CP System II",
|
||||
"CP System III",
|
||||
"Multi (various)",
|
||||
"Neo Geo"
|
||||
)
|
||||
|
||||
$retroarchMiscSystems = @(
|
||||
"2003 Game Engine",
|
||||
"4",
|
||||
"CHIP-8",
|
||||
"Handheld Electronic", #Handheld Electronic (GW)
|
||||
"LowRes NX", #LowRes NX
|
||||
"Magnavox Odyssey2", #133 Philips Videopac G7000
|
||||
"Mega Duck", # Mega Duck
|
||||
"Moonlight", # Moonlight,
|
||||
"PICO8", # PICO-8
|
||||
"Pong Game Clone", # Gong,
|
||||
"RPG Maker 2000",
|
||||
"SEGA Visual Memory Unit", #VeMUlator / Sega VMU
|
||||
"Uzebox" # Uzebox (Uzem)
|
||||
)
|
||||
|
||||
$raCoreNameToPlatformIdsTranslate = @{
|
||||
"Gearsystem" = @("sega_mastersystem", "sega_gamegear", "sega_sg1000", "coleco_vision");
|
||||
"Genesis Plus GX" = @("sega_mastersystem", "sega_gamegear", "sega_genesis", "sega_cd");
|
||||
"Genesis Plus GX Wide" = @("sega_mastersystem", "sega_gamegear", "sega_genesis", "sega_cd");
|
||||
"nSide (Super Famicom Accuracy)" = @("nintendo_super_nes", "nintendo_gameboy", "nintendo_gameboycolor");
|
||||
"PicoDrive" = @("sega_mastersystem", "sega_genesis", "sega_cd", "sega_32x");
|
||||
"SMS Plus GX" = @("sega_mastersystem", "sega_gamegear", "sega_sg1000", "coleco_vision");
|
||||
}
|
||||
|
||||
$raSystemIdToPlatformIdsTranslate = @{
|
||||
"msx" = @("microsoft_msx", "microsoft_msx2");
|
||||
"neo_geo_pocket" = @("snk_neogeopocket", "snk_neogeopocket_color");
|
||||
}
|
||||
|
||||
$raSystemNameToPlatformIdTranslate = @{
|
||||
"3DO" = "3do";
|
||||
"3DS" = "nintendo_3ds";
|
||||
"Amiga" = "commodore_amiga";
|
||||
"Atari 2600" = "atari_2600";
|
||||
"Atari 5200" = "atari_5200";
|
||||
"Atari 7800" = "atari_7800";
|
||||
"Atari ST" = "atari_st";
|
||||
"C128" = "commodore_64";
|
||||
"C64" = "commodore_64";
|
||||
"C64 SuperCPU" = "commodore_64";
|
||||
"CBM-5x0" = "commodore_cbm5x0";
|
||||
"CBM-II" = "commodore_cbm2";
|
||||
"CD" = "nec_turbografx_cd";
|
||||
"ColecoVision" = "coleco_vision";
|
||||
"Color" = "bandai_wonderswan_color";
|
||||
"Commodore Amiga" = "commodore_amiga";
|
||||
"CPC" = "amstrad_cpc";
|
||||
"DOS" = "pc_dos";
|
||||
"DS" = "nintendo_ds";
|
||||
"Falcon" = "atari_falcon030";
|
||||
"Game Boy" = "nintendo_gameboy";
|
||||
"Game Boy Advance" = "nintendo_gameboyadvance";
|
||||
"Game Boy Color" = "nintendo_gameboycolor";
|
||||
"GameCube" = "nintendo_gamecube";
|
||||
"GG" = "sega_gamegear";
|
||||
"Intellivision" = "mattel_intellivision";
|
||||
"Jaguar" = "atari_jaguar";
|
||||
"Lynx" = "atari_lynx";
|
||||
"Nintendo 64" = "nintendo_64";
|
||||
"Nintendo DS" = "nintendo_ds";
|
||||
"Nintendo Entertainment System" = "nintendo_nes";
|
||||
"PC" = "pc_dos";
|
||||
"PC Engine" = "nec_turbografx_16";
|
||||
"PC Engine SuperGrafx" = "nec_supergrafx";
|
||||
"PC-98" = "nec_pc98";
|
||||
"PC-FX" = "nec_pcfx";
|
||||
"PCE-CD" = "nec_turbografx_cd";
|
||||
"PET" = "commodore_pet";
|
||||
"PlayStation" = "sony_playstation";
|
||||
"PLUS" = "commodore_plus4";
|
||||
"PSP" = "sony_psp";
|
||||
"Saturn" = "sega_saturn";
|
||||
"Sega Dreamcast" = "sega_dreamcast";
|
||||
"Sega Genesis" = "sega_genesis";
|
||||
"Sega Master System" = "sega_mastersystem";
|
||||
"Sharp X68000" = "sharp_x68000";
|
||||
"SNK Neo Geo CD" = "snk_neogeo_cd";
|
||||
"Sony PlayStation 2" = "sony_playstation2";
|
||||
"STE" = "atari_st";
|
||||
"Super Nintendo Entertainment System" = "nintendo_super_nes";
|
||||
"SuperGrafx" = "nec_supergrafx";
|
||||
"Supervision" = "watara_supervision";
|
||||
"SVI" = "microsoft_msx";
|
||||
"Thomson MO" = "thomson_mo5";
|
||||
"TO" = "thomson_to7";
|
||||
"TT" = "atari_st"; # The Atari TT030 is a member of the Atari ST family
|
||||
"Vectrex" = "vectrex";
|
||||
"VIC-20" = "commodore_vci20";
|
||||
"Virtual Boy" = "nintendo_virtualboy";
|
||||
"Wii" = "nintendo_wii";
|
||||
"WonderSwan" = "bandai_wonderswan";
|
||||
"Xbox" = "xbox";
|
||||
"ZX Spectrum (various)" = "sinclair_zxspectrum";
|
||||
"ZX81" = "sinclair_zx81";
|
||||
}
|
||||
|
||||
$emuDefinitionTemplate = "Id: retroarch
|
||||
Name: RetroArch
|
||||
Website: 'http://www.retroarch.com/'
|
||||
Profiles:
|
||||
{0}"
|
||||
|
||||
$profileTemplate = ' - Name: {0}
|
||||
StartupArguments: ''-L ".\cores\{1}.dll" "{{ImagePath}}"''
|
||||
Platforms: [{2}]
|
||||
ImageExtensions: [{3}]
|
||||
ProfileFiles: [''cores\{4}.dll'']
|
||||
StartupExecutable: ^retroarch\.exe$'
|
||||
|
||||
$existingProfileReaddTemplate = ' - Name: {0}
|
||||
StartupArguments: ''{1}''
|
||||
Platforms: [{2}]
|
||||
ImageExtensions: [{3}]
|
||||
ProfileFiles: [''{4}'']
|
||||
StartupExecutable: ^retroarch\.exe$'
|
||||
|
||||
$existingEmuDefinition = Get-Content $retroArchEmuDefinitionPath -Raw | ConvertFrom-Yaml
|
||||
$usedProfileNames = @()
|
||||
$existingProfiles = @{}
|
||||
foreach ($existingProfile in $existingEmuDefinition.Profiles) {
|
||||
$existingProfiles[$existingProfile.ProfileFiles[0]] = $existingProfile
|
||||
$usedProfileNames += $existingProfile.Name
|
||||
}
|
||||
|
||||
$foundCoreNames = @()
|
||||
$foundPlatformIds = @()
|
||||
$profiles = @()
|
||||
$infoPath = Join-Path $RetroArchDir "info"
|
||||
$infoFiles = Get-ChildItem $infoPath -Filter "*.info"
|
||||
foreach ($infoFile in $infoFiles)
|
||||
{
|
||||
if ($ignoreList.Contains($infoFile.Name))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
$coreInfo = ParseInfoFile $infoFile.FullName
|
||||
$coreFile = "cores\{0}.dll" -f $infoFile.BaseName
|
||||
$platformIds = @()
|
||||
if ($existingProfiles.ContainsKey($coreFile))
|
||||
{
|
||||
$coreName = $existingProfiles[$coreFile].Name
|
||||
$platformIds = $existingProfiles[$coreFile].Platforms
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($usedProfileNames.Contains($coreInfo.corename))
|
||||
{
|
||||
$coreName = "{0} - {1}" -f $coreInfo.corename, $coreInfo.display_name
|
||||
}
|
||||
else
|
||||
{
|
||||
$coreName = $coreInfo.corename
|
||||
}
|
||||
}
|
||||
|
||||
if (!($coreInfo.ContainsKey("corename")))
|
||||
{
|
||||
Write-Host "$($infoFile.Name) does not contain the core name" -ForegroundColor Yellow # Some cores like anarch_libretro.info don't contain a core name
|
||||
continue
|
||||
}
|
||||
|
||||
$coreInfoCoreName = $coreInfo.corename
|
||||
if ($raCoreNameToPlatformIdsTranslate.ContainsKey($coreInfoCoreName))
|
||||
{
|
||||
$platformIds = $raCoreNameToPlatformIdsTranslate[$coreInfoCoreName]
|
||||
}
|
||||
elseif ($null -ne $coreInfo.systemid -and $raSystemIdToPlatformIdsTranslate.ContainsKey($coreInfo.systemid.Trim()))
|
||||
{
|
||||
$platformIds = $raSystemIdToPlatformIdsTranslate[$coreInfo.systemid.Trim()]
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!($coreInfo.ContainsKey("systemname")))
|
||||
{
|
||||
Write-Host "$($infoFile.Name) does not contain systemname" -ForegroundColor Yellow # galaksija_libretro.info
|
||||
continue
|
||||
}
|
||||
|
||||
$coreInfo.systemname.Split("/", [System.StringSplitOptions]::RemoveEmptyEntries) | ForEach-Object {
|
||||
$system = $_.Trim()
|
||||
if (($retroarchArcadeSystems -contains $system) -or ($retroarchMiscSystems -contains $system))
|
||||
{
|
||||
Continue
|
||||
}
|
||||
|
||||
if ($raSystemNameToPlatformIdTranslate.ContainsKey($system))
|
||||
{
|
||||
$platformId = $raSystemNameToPlatformIdTranslate[$system]
|
||||
if ($platformIds -notcontains $platformId)
|
||||
{
|
||||
$platformIds += $platformId
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "System to platform translate not found. System: $system, CoreName: $($coreInfo.corename), DisplayName: $($coreInfo.display_name)" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($null -eq $platformIds -or $platformIds.Count -eq 0)
|
||||
{
|
||||
Write-Host "PlatformIds not found. System: $system, CoreName: $($coreInfo.corename), DisplayName: $($coreInfo.display_name)" -ForegroundColor Yellow
|
||||
continue
|
||||
}
|
||||
|
||||
if ($coreInfo.supported_extensions)
|
||||
{
|
||||
$extensions = @()
|
||||
$coreInfo.supported_extensions.Split("|", [System.StringSplitOptions]::RemoveEmptyEntries) | ForEach-Object {
|
||||
$extensions += $_
|
||||
}
|
||||
|
||||
if ($extensions -notcontains "zip")
|
||||
{
|
||||
$extensions += "zip"
|
||||
}
|
||||
|
||||
if ($extensions -notcontains "7z")
|
||||
{
|
||||
$extensions += "7z"
|
||||
}
|
||||
|
||||
$extensions = $extensions | Sort-Object
|
||||
$extensionsString = [System.String]::Join(", ", $extensions)
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host "Profile did not have extensions. System: $system, CoreName: $($coreInfo.corename), DisplayName: $($coreInfo.display_name)" -ForegroundColor Yellow
|
||||
continue
|
||||
}
|
||||
|
||||
foreach ($platformId in $platformIds) {
|
||||
if ($foundPlatformIds -notcontains $platformId)
|
||||
{
|
||||
$foundPlatformIds += $platformId
|
||||
}
|
||||
}
|
||||
|
||||
$platformIds = $platformIds | Sort-Object
|
||||
$extensions = $extensions | Sort-Object
|
||||
$platformIdsString = [System.String]::Join(", ", $platformIds)
|
||||
$profileString = $profileTemplate -f $coreName, $infoFile.BaseName, $platformIdsString, $extensionsString, $infoFile.BaseName
|
||||
$profiles += $profileString
|
||||
$foundCoreNames += $coreName
|
||||
$usedProfileNames += $coreName
|
||||
}
|
||||
|
||||
# Previous profiles need to be kept or existing emulator configuration will break
|
||||
# Here emulators not generated will be added back
|
||||
foreach ($existingProfile in $existingEmuDefinition.Profiles) {
|
||||
if ($foundCoreNames -notcontains $existingProfile.Name)
|
||||
{
|
||||
foreach ($platformId in $existingProfile.Platforms) {
|
||||
if ($foundPlatformIds -notcontains $platformId)
|
||||
{
|
||||
$foundPlatformIds += $platformId
|
||||
}
|
||||
}
|
||||
|
||||
$platformIds = [System.String]::Join(", ", ($existingProfile.Platforms | Sort-Object))
|
||||
$extensionsString = [System.String]::Join(", ", ($existingProfile.ImageExtensions | Sort-Object))
|
||||
$profileFilesString = [System.String]::Join(", ", ($existingProfile.ProfileFiles | Sort-Object))
|
||||
$profileString = $existingProfileReaddTemplate -f $existingProfile.Name, $existingProfile.StartupArguments, $platformIds, $extensionsString, $profileFilesString
|
||||
$profiles += $profileString
|
||||
Write-Host "Existing profile $($existingProfile.Name) not found in newly generated definition and was added back from previous definition" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
|
||||
# Join generated profiles and validated created profile yaml content
|
||||
$profiles = $profiles | Sort-Object
|
||||
$profilesString = [System.String]::Join("`n`n", $profiles)
|
||||
$emuDefinitionContent = $emuDefinitionTemplate -f $profilesString
|
||||
if ((Get-IsYamlValid $emuDefinitionContent) -eq $false)
|
||||
{
|
||||
Write-Host "Newly generated profile definition file is not valid!" -ForegroundColor Red
|
||||
Set-Clipboard $emuDefinitionContent
|
||||
return
|
||||
}
|
||||
|
||||
# Add RetroArch to emulators list in Playnite platforms definitions
|
||||
$platformDefinitionTemplate = '- Name: {0}
|
||||
{1}'
|
||||
|
||||
$newPlatformsDefinitions = @()
|
||||
$existingPlatformsDefinition = Get-Content $platformsDefinitionPath -Raw | ConvertFrom-Yaml
|
||||
foreach ($platform in $existingPlatformsDefinition) {
|
||||
$platformData = @()
|
||||
$platformData += " Id: {0}" -f $platform.Id
|
||||
if ($platform.IgdbId)
|
||||
{
|
||||
$platformData += "IgdbId: {0}" -f $platform.IgdbId
|
||||
}
|
||||
|
||||
if ($platform.Databases)
|
||||
{
|
||||
$platformData += "Databases: [{0}]" -f [System.String]::Join(", ", ($platform.Databases | Sort-Object))
|
||||
}
|
||||
|
||||
$isSupportedByRetroArch = $foundPlatformIds -contains $platform.Id
|
||||
if ($platform.Emulators)
|
||||
{
|
||||
if ($isSupportedByRetroArch -and ($platform.Emulators -notcontains "retroarch"))
|
||||
{
|
||||
$platform.Emulators += "retroarch"
|
||||
$platform.Emulators = $platform.Emulators | Sort-Object
|
||||
Write-Host "Added retroarch emulator to `"$($platform.Name)`" platform" -ForegroundColor Blue
|
||||
}
|
||||
$platformData += "Emulators: [{0}]" -f [System.String]::Join(", ", ($platform.Emulators | Sort-Object))
|
||||
}
|
||||
elseif ($isSupportedByRetroArch)
|
||||
{
|
||||
$platformData += "Emulators: [{0}]" -f "retroarch"
|
||||
}
|
||||
|
||||
$platformDataString = $platformDefinitionTemplate -f $platform.Name, [System.String]::Join("`n ", $platformData)
|
||||
$newPlatformsDefinitions += $platformDataString
|
||||
}
|
||||
|
||||
$newPlatformsDefinitionsContent = [System.String]::Join("`n `n", $newPlatformsDefinitions)
|
||||
|
||||
# Validate created platforms definition yaml content
|
||||
if ((Get-IsYamlValid $newPlatformsDefinitionsContent) -eq $false)
|
||||
{
|
||||
Write-Host "Newly generated platforms definition file is not valid!" -ForegroundColor Red
|
||||
Set-Clipboard $newPlatformsDefinitionsContent
|
||||
return
|
||||
}
|
||||
|
||||
# Save generated yaml files. New lines are replaced to maintain CRLF endings
|
||||
[System.IO.File]::WriteAllLines($retroArchEmuDefinitionPath, $emuDefinitionContent.Replace("`n","`r`n"), [System.Text.Encoding]::UTF8)
|
||||
[System.IO.File]::WriteAllLines($platformsDefinitionPath, $newPlatformsDefinitionsContent.Replace("`n","`r`n"), [System.Text.Encoding]::UTF8)
|
||||
Write-Host "RetroArch emulator and Playnite platforms definitions updated and saved successfully!" -ForegroundColor Green
|
||||
@ -1,3 +1,5 @@
|
||||
#Requires -Version 7
|
||||
|
||||
param(
|
||||
[string]$AccessToken
|
||||
)
|
||||
@ -11,18 +13,20 @@ $requestHeaders = @{
|
||||
"Authorization" = "Bearer $AccessToken"
|
||||
}
|
||||
|
||||
$locProgressData = @{}
|
||||
$locProgress = Invoke-RestMethod -Headers $requestHeaders -Uri "$urlRoot/projects/$playnitePrjId/languages/progress?limit=100"
|
||||
$locProgressData = New-Object "System.Collections.Specialized.OrderedDictionary"
|
||||
$locProgress = Invoke-RestMethod -Method Get -Headers $requestHeaders -Uri "$urlRoot/projects/$playnitePrjId/files/30/languages/progress?limit=100" ` -ContentType "application/json"
|
||||
foreach ($lng in $locProgress.data)
|
||||
{
|
||||
$locProgressData.Add($lng.data.languageId, $lng.data.translationProgress);
|
||||
$locDownloadData = Invoke-RestMethod -Method Post -Headers $requestHeaders -Uri "$urlRoot/projects/$playnitePrjId/translations/builds/files/30" `
|
||||
-Body "{`"targetLanguageId`":`"$($lng.data.languageId)`"}" -ContentType "application/json"
|
||||
|
||||
$locDownload = Invoke-WebRequest -Uri $locDownloadData.data.url
|
||||
$tempFile = Join-Path $locDir "temp.xaml"
|
||||
Remove-Item $tempFile -EA 0
|
||||
$locDownload = Invoke-WebRequest -Uri $locDownloadData.data.url -OutFile $tempFile -PassThru
|
||||
$locDownload.Headers["Content-Disposition"][0] -match '"(.+)"' | Out-Null
|
||||
$fileName = $Matches[1]
|
||||
[System.IO.File]::WriteAllBytes((Join-Path $locDir $fileName), $locDownload.Content)
|
||||
Move-Item $tempFile (Join-Path $locDir $fileName) -Force
|
||||
}
|
||||
|
||||
$locProgressData | ConvertTo-Json | Out-File (Join-Path $locDir "locstatus.json")
|
||||
|
||||
9
doc/.gitignore
vendored
9
doc/.gitignore
vendored
@ -1,9 +0,0 @@
|
||||
###############
|
||||
# folder #
|
||||
###############
|
||||
/**/DROP/
|
||||
/**/TEMP/
|
||||
/**/packages/
|
||||
/**/bin/
|
||||
/**/obj/
|
||||
_site
|
||||
@ -1,7 +0,0 @@
|
||||
apiRules:
|
||||
- exclude:
|
||||
uidRegex: ^System\.Collections\.Concurrent$
|
||||
type: Namespace
|
||||
- exclude:
|
||||
uidRegex: ^Playnite\.SDK\.Converters$
|
||||
type: Namespace
|
||||
4
doc/api/.gitignore
vendored
4
doc/api/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
###############
|
||||
# temp file #
|
||||
###############
|
||||
*.yml
|
||||
1308
doc/api/.manifest
1308
doc/api/.manifest
File diff suppressed because it is too large
Load Diff
@ -1,3 +0,0 @@
|
||||
# Playnite API documentation
|
||||
|
||||
SDK can be obtained as [nuget package](https://www.nuget.org/packages/PlayniteSDK/) (recommended) or built from source project `PlayniteSDK`.
|
||||
153
doc/changelog.md
153
doc/changelog.md
@ -1,153 +0,0 @@
|
||||
### To get automatically notified about SDK changes, you can subscribe to [change tracking issue](https://github.com/JosefNemec/Playnite/issues/1425) on GitHub.
|
||||
|
||||
#### 6.2.0
|
||||
|
||||
* New
|
||||
* [Added](https://playnite.link/sdkchangelog/6.1.0-6.2.0/PlayniteSDK_Events_ApplicationEvents.cs.html) selected ROM file and source game action to game starting events.
|
||||
* [Exposed](https://playnite.link/sdkchangelog/6.1.0-6.2.0/PlayniteSDK_IMainViewAPI.cs.html) selected Desktop view mode in UI API.
|
||||
* [Added](https://playnite.link/sdkchangelog/6.1.0-6.2.0/PlayniteSDK_IMainViewAPI.cs.html) option to select multiple games.
|
||||
* [Exposed](https://playnite.link/sdkchangelog/6.1.0-6.2.0/PlayniteSDK_IMainViewAPI.cs.html) list of currently filtered games.
|
||||
* [Exposed](https://playnite.link/sdkchangelog/6.1.0-6.2.0/PlayniteSDK_IPlayniteSettingsAPI.cs.html) completion status settings.
|
||||
* [Added](https://playnite.link/sdkchangelog/6.1.0-6.2.0/PlayniteSDK_IWebView.cs.html) option to set user agent for specific web view instance.
|
||||
* New [model changes](https://playnite.link/sdkchangelog/6.1.0-6.2.0/PlayniteSDK_Models_Emulator.cs.html) related to added option to override built-in emulator arguments.
|
||||
|
||||
#### 6.1.0
|
||||
|
||||
* New
|
||||
* `IsMusicMuted` property exposed in settings API.
|
||||
|
||||
#### 6.0.0
|
||||
|
||||
* **Breaking Changes**
|
||||
* **Many** breaking changes to the entire SDK. All extensions and themes have to updated to work with Playnite 9. See [Playnite 9 migration guide](tutorials/playnite9migration.md) for more details.
|
||||
* Removed IronPython support.
|
||||
* Extensions no longer log into main `playnite.log` log file, but instead log into separate `extensions.log` file.
|
||||
* Playnite 9 changes how library files are stored on disk. This is not breaking change to the SDK, but some existing extensions modify library files directly (which was never supported) and those will not work anymore.
|
||||
|
||||
* New
|
||||
* PowerShell extensions are now implemented as proper PowerShell modules.
|
||||
* Playnite now includes built-in add-on browser that can be used to install/update extension. You need to publish your extension to [add-on repository](https://github.com/JosefNemec/PlayniteAddonDatabase) for it to work.
|
||||
* Ability to inject elements into Sidebar, Top panel and any custom theme that supports specific extension element explicitly.
|
||||
* Ability to dynamically inject play, install and uninstall actions.
|
||||
* You can now load extensions from custom directories via `For developers` settings menu.
|
||||
* Added `Trace` severity log messages. These are not written into log files unless enabled in `For developers` settings menu.
|
||||
* Import exclusions can be controlled via the SDK.
|
||||
* Themes can now add [custom mouse cursor](tutorials/themes/various.md#custom-mouse-cursor) and [sound files](tutorials/themes/various.md#changing-audio-files).
|
||||
|
||||
#### 5.5.0
|
||||
|
||||
* New
|
||||
* Ability to change progress text when using [ActivateGlobalProgress](xref:Playnite.SDK.IDialogsFactory)
|
||||
* `CurrentExtensionInstallPath` and `CurrentExtensionDataPath` global variables for script extensions
|
||||
|
||||
#### 5.4.0
|
||||
|
||||
* New
|
||||
* [ActivateGlobalProgress](xref:Playnite.SDK.IDialogsFactory) can now report specific progress status.
|
||||
* [CanExecuteJavascriptInMainFrame](xref:Playnite.SDK.IWebView) property for WebViews.
|
||||
* Various [data serialization methods](xref:Playnite.SDK.Data.Serialization) (JSON, YAML, TOML)
|
||||
* [CreateWindow](xref:Playnite.SDK.IDialogsFactory) for creating native Playnite windows with styling.
|
||||
* [GetCurrentAppWindow](xref:Playnite.SDK.IDialogsFactory) to get currently active Playnite window.
|
||||
|
||||
#### 5.3.0
|
||||
|
||||
* **Breaking Changes**:
|
||||
* Playnite will no longer load plugins that reference non-SDK Playnite assemblies. See [this page](tutorials/extensions/plugins.md#referencing-playnite-assemblies) for more information.
|
||||
* Playnite will no longer install extensions and themes that don't have proper version specified. The version string must a valid [.NET version string](https://docs.microsoft.com/en-us/dotnet/api/system.version)!
|
||||
|
||||
* **Now obsolete**:
|
||||
|
||||
* These changes do not break compatibility in current version (mentioned methods are still available in SDK), but they will be made breaking in future major Playnite updates.
|
||||
* Added `Id` to extension and theme [manifests](tutorials/extensions/extensionsManifest.md). This field is currently not mandatory for existing extensions (Playnite 8 will load installed extensions without an ID, but will not install new ones without an ID), but should be provided for better extension installation and update support. Toolbox will not pack new extensions unless `Id` is present.
|
||||
* The way custom menu items are implemented (for main menu and game menu) has been completely changed (the old system still works temporarily). See [related documentation page](tutorials/extensions/menus.md) for more information.
|
||||
* [NavigationChanged](xref:Playnite.SDK.IWebView) from IWebView is now obsolete, use new `LoadingChanged` instead.
|
||||
|
||||
* New
|
||||
* Metadata plugins can now provide `Features`, `AgeRating`, `Series`, `Region` and `Platform` data.
|
||||
* Extensions can now provide [custom menu items](tutorials/extensions/menus.md) for game menus, including nested entries.
|
||||
* Most useful Playnite settings are now exposed in [IPlayniteSettingsAPI](xref:Playnite.SDK.IPlayniteSettingsAPI).
|
||||
* [ActivateGlobalProgress](xref:Playnite.SDK.IDialogsFactory) method to show blocking progress dialog.
|
||||
* [LoadingChanged](xref:Playnite.SDK.IWebView) event for WebViews.
|
||||
* [EvaluateScriptAsync](xref:Playnite.SDK.IWebView) method to execute JS code in a WebView.
|
||||
* [GetCookies](xref:Playnite.SDK.IWebView) method to get webview cookies.
|
||||
* [MarkdownToHtml](xref:Playnite.SDK.Data.Markup.MarkdownToHtml(System.String)) method for converting Markdown markup to HTML.
|
||||
|
||||
#### 5.2.0
|
||||
|
||||
* **Breaking Changes**:
|
||||
* [Toolbox](tutorials/toolbox.md) utility has been reworked and accepts different arguments then previously.
|
||||
|
||||
* New
|
||||
* Library plugins can now support extra [capabilities](tutorials/extensions/libraryPlugins.md#capabilities).
|
||||
* Added [ImportGame](xref:Playnite.SDK.IGameDatabase.ImportGame(Playnite.SDK.Models.GameInfo)) methods to more easily add new games to the library.
|
||||
* Added [OpenPluginSettings](xref:Playnite.SDK.IMainViewAPI.OpenPluginSettings(System.Guid)) method to open view with extension settings (also accessible via `OpenSettingsView` method inherited from `Plugin` class).
|
||||
* Added [StartGame](xref:Playnite.SDK.IPlayniteAPI.StartGame(System.Guid)).
|
||||
* Added [UriHandler](xref:Playnite.SDK.IPlayniteAPI.UriHandler) for registering of custom [URI method actions](tutorials/extensions/uriSupport.md).
|
||||
* Added option settings when creating offscreen web view (currently only option to disable JavaScript execution).
|
||||
* Added `OnGameSelected`, `OnApplicationStopped` and `OnLibraryUpdated` events.
|
||||
* Added `Features` game field and appropriate support for it in metadata plugins.
|
||||
* [Toolbox](tutorials/toolbox.md) utility can now generate plugins and scripts.
|
||||
* [Toolbox](tutorials/toolbox.md) utility can pack plugins and scripts into `.pext` file that can be used for easier distribution and installation.
|
||||
|
||||
#### 5.1.0
|
||||
|
||||
* New
|
||||
* Added support for creating metadata providers via [plugins](tutorials/extensions/metadataPlugins.md).
|
||||
* [ChooseImageFile](xref:Playnite.SDK.IDialogsFactory) method for dialogs API. **Only available in Desktop mode.**
|
||||
* [ChooseItemWithSearch](xref:Playnite.SDK.IDialogsFactory) method for dialogs API. **Only available in Desktop mode.**
|
||||
|
||||
#### 5.0.1
|
||||
|
||||
* Removed reference to LiteDB package. You can remove it from your plugin project if it's present.
|
||||
|
||||
|
||||
#### 5.0.0
|
||||
|
||||
* **Breaking Changes**:
|
||||
* Extension plugins are no longer created by inheriting plugin interface, but rather extending [Plugin](xref:Playnite.SDK.Plugins.Plugin) and [LibraryPlugin](xref:Playnite.SDK.Plugins.LibraryPlugin) abstract classes.
|
||||
* [IGameDatabase](xref:Playnite.SDK.IGameDatabase) interface is completely changed and every object collection (Games, Genres, Tags etc.) is now accessible via appropriate `IItemCollection` property.
|
||||
* [Game](xref:Playnite.SDK.Models.Game) changed dramatically. Fields like genres, tags and others are no longer part of the model itself but just ID pointers to appropriate database objects.
|
||||
|
||||
* New
|
||||
* Extended several API with new methods.
|
||||
|
||||
#### 3.0.0
|
||||
|
||||
* **Breaking Changes**:
|
||||
* Removed and added new APIs and API members.
|
||||
* Game files are no longer stored in single database file. All game and media files are now accessible in their raw form even without user of database API.
|
||||
|
||||
#### 2.0.0
|
||||
|
||||
* **Breaking Changes**:
|
||||
* In order to unify terminology used in Playnite's UI and that in SDK, some classes and class members were renamed.
|
||||
* Extensions (both plugins and scripts) have to provide [extension manifest](tutorials/extensions/extensionsManifest.md) otherwise they won't be loaded.
|
||||
* Various information about extension (author, version etc.) must be now stored in manifest file.
|
||||
* Both plugins and scripts have to be stored in the same folder called `Extensions` (rather then in separate `Plugins` or `Scripts` folders).
|
||||
* Signature for default C# plugins has changed and they now have to implement `IGenericPlugin` interface to be loaded.
|
||||
|
||||
* New Plugin types. There are now two types of plugins that can be implemented:
|
||||
* Generic Plugin: Same as the old plugins.
|
||||
* [Library Plugin](tutorials/extensions/libraryPlugins.md): Used to add new library providers responsible for automatic game import from various sources.
|
||||
* All existing supported library importers (Steam, GOG etc.) are now distributed as [library plugins](https://github.com/JosefNemec/Playnite/tree/master/source/Plugins).
|
||||
|
||||
* New APIs:
|
||||
* Static [LogManager](xref:Playnite.SDK.LogManager) for easier log operations.
|
||||
* [Web Views API](xref:Playnite.SDK.IWebView) for creating web view windows or accessing offscreen browser.
|
||||
* [Resources API](xref:Playnite.SDK.IPlayniteAPI.Resources) for getting application resources like localized strings.
|
||||
* [Paths API](xref:Playnite.SDK.IPlayniteAPI.Paths) providing information about Playnite's application paths.
|
||||
* [Application Info API](xref:Playnite.SDK.IPlayniteAPI.ApplicationInfo) providing information about Playnite.
|
||||
|
||||
* New Methods
|
||||
* GetPluginUserDataPath: Gets path dedicated for plugins to store user data.
|
||||
* GetPluginConfiguration: Gets plugin configuration if available.
|
||||
* LoadPluginSettings: Loads plugin settings.
|
||||
* SavePluginSettings: Saves plugin settings.
|
||||
* ExpandGameVariables: Expands dynamic game variables in specified game action.
|
||||
* CreateLogger: Creates new instance of Playnite logger with name of calling class.
|
||||
|
||||
#### 1.1.0
|
||||
|
||||
* **Breaking Change**: Scripts and Plugins must be place in subfolders rather then directly inside of `Scripts` or `Plugins` folders.
|
||||
* New: `OnGameStarting` event that will execute before game is started. See [events](tutorials/extensions/events.md) for use from scripts.
|
||||
* New: [ShowErrorMessage](xref:Playnite.SDK.IDialogsFactory.ShowErrorMessage(System.String,System.String)) method in `IDialogsFactory`
|
||||
@ -1,70 +0,0 @@
|
||||
{
|
||||
"metadata": [
|
||||
{
|
||||
"src": [
|
||||
{
|
||||
"files": [
|
||||
"**.csproj"
|
||||
],
|
||||
"exclude": [
|
||||
"**/bin/**",
|
||||
"**/obj/**",
|
||||
"_site/**"
|
||||
],
|
||||
"src" : "../source/PlayniteSDK/"
|
||||
}
|
||||
],
|
||||
"dest": "api",
|
||||
"disableGitFeatures": false,
|
||||
"filter": "SDKfilter.yml"
|
||||
}
|
||||
],
|
||||
"build": {
|
||||
"content": [
|
||||
{
|
||||
"files": [
|
||||
"api/**.yml",
|
||||
"api/index.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"tutorials/**.md",
|
||||
"tutorials/**/toc.yml",
|
||||
"manual/**.md",
|
||||
"manual/**/toc.yml",
|
||||
"toc.yml",
|
||||
"*.md"
|
||||
]
|
||||
}
|
||||
],
|
||||
"resource": [
|
||||
{
|
||||
"files": [ "**/images/**" ]
|
||||
}
|
||||
],
|
||||
"overwrite": [
|
||||
{
|
||||
"files": [
|
||||
"apidoc/**.md"
|
||||
],
|
||||
"exclude": [
|
||||
"obj/**",
|
||||
"_site/**"
|
||||
]
|
||||
}
|
||||
],
|
||||
"dest": "_site",
|
||||
"globalMetadataFiles": [],
|
||||
"fileMetadataFiles": [],
|
||||
"template": [
|
||||
"default",
|
||||
"templates/playnite"
|
||||
],
|
||||
"postProcessors": [],
|
||||
"noLangKeyword": false,
|
||||
"keepFileLink": false,
|
||||
"cleanupCacheHistory": false,
|
||||
"disableGitFeatures": false
|
||||
}
|
||||
}
|
||||
20
doc/index.md
20
doc/index.md
@ -1,20 +0,0 @@
|
||||
# Playnite SDK documentation
|
||||
|
||||
> [!NOTE]
|
||||
> There's currently very active community around theme/extension development on our [Discord server](https://discord.gg/hSFvmN6). We highly recommend joining if you plan to develop add-ons for Playnite!
|
||||
|
||||
### Extensions
|
||||
|
||||
To get documentation and tutorials on how to extend Playnite's functionality with scripts and plugins see [extension tutorials](tutorials/extensions/intro.md) page.
|
||||
|
||||
### Themes
|
||||
|
||||
To get documentation and about custom themes see [themes introduction](tutorials/themes/introduction.md) page.
|
||||
|
||||
### API Documentation
|
||||
|
||||
Full documentation for SDK interfaces and classes is available on [API Documentation](api/index.md) page.
|
||||
|
||||
### Changelog
|
||||
|
||||
See [changelog](changelog.md) page for full list of API changes.
|
||||
@ -1,27 +0,0 @@
|
||||
Application arguments
|
||||
=====================
|
||||
|
||||
Playnite executable accepts following arguments from command line.
|
||||
|
||||
| Argument | Description |
|
||||
| -- | -- |
|
||||
| --start <gameId> | Starts game with specified library ID. |
|
||||
| --nolibupdate | Skips library update on startup. |
|
||||
| --startdesktop | Forces application to start in Desktop mode. If there's an existing instance already running in Fullscreen mode, it will be switched to Desktop mode. |
|
||||
| --startfullscreen | Forces application to start in Fullscreen mode. If there's an existing instance already running in Desktop mode, it will be switched to Fullscreen mode. | |
|
||||
| --forcesoftrender | Forces application to use software render, disabling GPU acceleration. |
|
||||
| --forcedefaulttheme | Forces application to use default theme. |
|
||||
| --hidesplashscreen | Won't show startup splash screen. |
|
||||
| --clearwebcache | Clears web (CEF) cache on startup. |
|
||||
| --shutdown | Shuts down any existing instances of Playnite. |
|
||||
| --safestartup | Start playnite in Safe Mode, only loading built-in extensions and using default theme. |
|
||||
|
||||
URI commands
|
||||
---------------------
|
||||
|
||||
| Command | Description | Example |
|
||||
| -- | -- | -- |
|
||||
| start | Start a game. | playnite://playnite/start/64f78cd1-0b00-4271-a9e1-89abc55f66cc |
|
||||
| showgame | Show game details for specific game. | playnite://playnite/showgame/64f78cd1-0b00-4271-a9e1-89abc55f66cc |
|
||||
|
||||
Extensions can register custom commands via [Playnite SDK](../tutorials/extensions/uriSupport.md).
|
||||
@ -1,129 +0,0 @@
|
||||
Emulator support
|
||||
=====================
|
||||
|
||||
General import guide
|
||||
---------------------
|
||||
|
||||
General workflow for importing games is:
|
||||
|
||||
- Setup an emulator via Library -> Configure Emulators menu.
|
||||
- Playnite can automatically import several well known emulators and will set all emulator properties for you. To import an emulator use `Import` button on configuration window.
|
||||
- See [Emulator support](#emulator-configuration) section for more details about emulator setup.
|
||||
- Import game image(s) (ROMs) via Add Game -> Emulated Game menu.
|
||||
- See [Game import support](#game-import-support) section for more details.
|
||||
- If you want the same directory to be re-scanned on startup (or manually) enable "Save as auto-scan" option. You can later edit saved scanner from emulator configuration window, "Auto-scan configuration" tab.
|
||||
|
||||
> [!NOTE]
|
||||
> It's highly recommended to use automatically imported emulators and built-in profiles for better game import experience. Some built-in emulators (for example RPCS3 and ScummVM) use more advanced import mechanism then just matching file names and you won't be able to utilize it with custom profiles.
|
||||
|
||||
> [!NOTE]
|
||||
> Playnite currently doesn't have built-in support for any arcade emulator. You will have to configure those manually. Built-in support for more well known arcade emulators will be added [in future](https://github.com/JosefNemec/Playnite/issues/2407). If you are having issues with non-arcade emulators, please open GitHub issue (games not being imported or launched properly).
|
||||
|
||||
Emulator support
|
||||
---------------------
|
||||
|
||||
Playnite has a support for handling and importing of emulated games. The support is implemented in two ways:
|
||||
|
||||
`Built-in support`: Playnite can recognize and import several known [emulators](https://github.com/JosefNemec/Playnite/tree/master/source/Playnite/Emulation/Emulators). This also includes import of emulated based on libretro game database.
|
||||
|
||||
If you think that there's an emulator that should be added to built-in list, please [open new issue on GitHub](https://github.com/JosefNemec/Playnite/issues/) for it to be added.
|
||||
|
||||
`Custom support`: You can manually configure any emulator that provides a way of launching specific games via command line arguments. Automatic game import might not be as accurate as in case of built-in profiles, since custom emulators only provide scanning based on a file name and file extension.
|
||||
|
||||
Emulator configuration
|
||||
---------------------
|
||||
|
||||
Recommend way of adding new emulator is by importing it. If an emulator is recognized as support emulator, it will be show on import dialog with an option to select which emulator profiles to import. Some emulators support multiple profiles, which affect how a game is started and imported.
|
||||
|
||||
Alternatively you can add new emulator manually if built-in support doesn't work in a way you prefer, or you can just add custom profile to automatically imported built-in emulator.
|
||||
|
||||
### Emulator properties
|
||||
|
||||
| Property | Description |
|
||||
| --- | --- |
|
||||
| Installation Folder | Emulator's installation folder. Can be passed into profile configurations dynamically via `{EmulatorDir}` variable.
|
||||
| Emulator specification | Built-in emulator specification used for an emulator. Specifies what built-in profiles can be added to an emulator.
|
||||
|
||||
### Profile properties
|
||||
|
||||
Profiles handle how game is started and imported.
|
||||
|
||||
| Property | Description |
|
||||
| --- | --- |
|
||||
| Executable | File path to start an emulator. |
|
||||
| Arguments | Startup arguments passed to an emulator during startup. |
|
||||
| Working Directory | Working directory set to an emulator during startup. |
|
||||
| Supported file types | File extensions separated by `,`. Used to detect ROM files by this profile. If you need to specify empty extension, use `<none>`. |
|
||||
| Scripts | Profiles can execute custom scripts in the same way as [game or global scripts](gameScripts.md). |
|
||||
|
||||
### Startup script
|
||||
|
||||
If your profile contains `Startup script` code, Playnite will use that instead of general profile settings to launch an emulator. Emulator startup scripts works in the same way as [game startup scripts](gameScripts.md#startup-script). The only different is that emulator script have some additional variables available:
|
||||
|
||||
| Variable | Description |
|
||||
| :-- | :-- |
|
||||
| Emulator | [Emulator](xref:Playnite.SDK.Models.Emulator) selected to launch a game. |
|
||||
| EmulatorProfile | [Emulator profile](xref:Playnite.SDK.Models.EmulatorProfile) selected to launch a game. |
|
||||
| RomPath | ROM path selected to launch. |
|
||||
|
||||
### Custom profile example
|
||||
|
||||
Following example show how to configure `snex9x` emulator:
|
||||
- Installation folder: `c:\some path\to\snes9x\`
|
||||
- Executable: `{EmulatorDir}\snes9x.exe`
|
||||
- Arguments: `"{ImagePath}" -fullscreen`
|
||||
- Supported File Types: `zip, gz, jma, sfc, smc`
|
||||
|
||||
> [!NOTE]
|
||||
> A lot of arcade emulators require ROM file to be passed via command line argument as a file name without complete path or file name without an extension. In that case you can use `{ImageName}` or `{ImageNameNoExt}` [game variables](gameVariables.md), instead of {ImagePath} which contains full path to a ROM file.
|
||||
|
||||
Game import support
|
||||
---------------------
|
||||
|
||||
To import a game you need configure a scanner first. How games are imported is controller by an emulator and its selected profile. Built-in emulators/profiles use several different method how to detect a game.
|
||||
|
||||
Custom profiles primarily match games by specified file extensions. If you want to increase accuracy of the import, make sure you also assign correct platforms to the profile and that those platforms have [platform specification](libraryManager.md#platform-specification) assigned to them.
|
||||
|
||||
Playnite by default groups multi-disc games under one game entry. You can alternatively split or merge these via right-click menu after selecting games on import list. Right-click menu also gives you an ability to change platform and region in bulk.
|
||||
|
||||
Auto-scan configurations
|
||||
---------------------
|
||||
|
||||
Scanner configurations can be used to automatically add new games during library import via `Update Game Library` menu. Specific configurations can be excluded from global library update on scanner configurations screen via `Library -> Configure Emulators` menu.
|
||||
|
||||
### Exclude patterns
|
||||
|
||||
These specify file patterns used during checksum scan. When a file matches specified pattern(s), its checksum won't be calculated and game will be imported based on other ROM properties (mainly file name). This can significantly speed up scanning process but also make import less accurate.
|
||||
|
||||
Multiple patterns can be specified by separating the list with comma: `*.chd,*.iso`
|
||||
|
||||
> [!NOTE]
|
||||
> `chd` files are excluded by default because there are currently no records for them in emulation database Playnite uses for game matching.
|
||||
|
||||
Launching games
|
||||
---------------------
|
||||
|
||||
If a game is imported via emulation import dialog, Playnite configures game launch via specific emulator (the one used to scan and import games) automatically. If you add a game manually, you can configure launch via an emulator by adding Emulator type [Play action](gameActions.md).
|
||||
|
||||
If a game has multiple ROM files assigned to it (on `Installation` tab while editing a game), Playnite will show selection during during game's startup, to specify which ROM should be passed to an emulator.
|
||||
|
||||
Troubleshooting
|
||||
---------------------
|
||||
|
||||
If you encounter any issue when using built-in emulator configurations/profiles, please [open new issue on GitHub](https://github.com/JosefNemec/Playnite/issues/) to let us know and we will fix it.
|
||||
|
||||
### Emulator doesn't start
|
||||
|
||||
Usually occurs when using custom profile if executable path is not properly configured. Make sure that problematic profile points to an existing file.
|
||||
|
||||
### Emulator is not being imported
|
||||
|
||||
Playnite either doesn't have a profile for the emulator or the emulator has been updated in a way that prevents Playnite from detect it. In both case, please report an issue on GitHub
|
||||
|
||||
### Emulator starts, but game is not launched
|
||||
|
||||
This is usually caused by wrongly configured profile `Arguments` that are passed to the emulator. Make sure that arguments are configured according to what selected emulator supports (by checking its documentation).
|
||||
|
||||
### Game ROMs are not detected
|
||||
|
||||
When using custom emulator configurations, Playnite uses `Supported File Types` profile property to scan files ROM files. Make sure you have correct extensions specified.
|
||||
@ -1,55 +0,0 @@
|
||||
Game actions
|
||||
=====================
|
||||
|
||||
Introduction
|
||||
---------------------
|
||||
|
||||
Game actions can be use either to start a game or to launch additional executables not related to game startup, for example configuration/mod utilities. Only actions marked as "Play" action are used to start a game, others are available to launch via game menu. If more then one Play action is available, Playnite will show selection dialog on game's startup to specify which action to use to start a game.
|
||||
|
||||
`Include library integration play actions` specifies whether integration plugin that imported a specific game, will be asked to handle game startup when the game is being launched.
|
||||
|
||||
Play actions can be also provided by plugins, see [game actions](../tutorials/extensions/gameActions.md) plugin page for more details.
|
||||
|
||||
Action properties
|
||||
---------------------
|
||||
|
||||
| Property | Description |
|
||||
| --- | --- |
|
||||
| Play action | If enabled, Playnite will treat this action as Play action. Offering as an option when starting a game (if more than one option is available and counting play time from a started by this action. |
|
||||
| Type | Action startup type. |
|
||||
| Tracking mode | Only available for Play actions (`File` and `URL` types) since it affects how play time detection works. |
|
||||
| Path | File path (or URL) to start. |
|
||||
| Arguments | Startup arguments passed to an executable during startup. |
|
||||
| Working directory | Working directory set to an executable during startup. |
|
||||
|
||||
### Action types
|
||||
|
||||
| Property | Description |
|
||||
| --- | --- |
|
||||
| File | Path is executed as a standard executable file. |
|
||||
| URL | Path is executed as an URL address. |
|
||||
| Emulator | Action is started using emulator configuration. |
|
||||
| Script | Script used to start an application. See [game scripts](gameScripts.md#startup-script) page for more details. |
|
||||
|
||||
> [!WARNING]
|
||||
> Non-play actions that use `Script` startup method will run synchronously on main thead. This means that they will block Playnite's UI until the script is finished running. Therefore make sure you don't use any long running operations in your startup script.
|
||||
|
||||
### Emulator settings
|
||||
|
||||
| Property | Description |
|
||||
| --- | --- |
|
||||
| Emulator | Emulator to launch. |
|
||||
| Emulator profile | Emulator profile to use to launch a game. Selecting `Choose on startup` will give an option to select a profile |
|
||||
|
||||
### Tracking mode
|
||||
|
||||
| Property | Description |
|
||||
| --- | --- |
|
||||
| Default | Playnite will try to detect and use the best tracking method automatically. |
|
||||
| Process | Playnite will track a game as running as long as original process or any of its child processes are running. |
|
||||
| Folder | Playnite will track a game as running as long as some process from `Tracking path` folder is running. |
|
||||
|
||||
Troubleshooting
|
||||
---------------------
|
||||
|
||||
In rare cases (depending on an application being started) the application won't start properly unless `Working directory` is not set to application's installation directory. If this happens you need to specify `Working directory` manually to a directory that makes selected application run properly. This is not an issue in Playnite, it's an issue in the started application.
|
||||
@ -1,164 +0,0 @@
|
||||
Game scripts
|
||||
=====================
|
||||
|
||||
Introduction
|
||||
---------------------
|
||||
|
||||
Custom PowerShell scripts can be assigned via Playnite's UI to game events. This is similar in a way that extensions support hooking into game events, but doesn't require creation of custom extension and can be assigned on multiple levels:
|
||||
|
||||
- Global: executed for every game in a library.
|
||||
- Emulator: executed for a specific emulator profile on all games using that profile.
|
||||
- Game: executed for a specific game.
|
||||
|
||||
This is not the same as [script extensions](../tutorials/extensions/intro.md) which offer extended functionality and should be used for more complex scenarios.
|
||||
|
||||
> [!NOTE]
|
||||
> PowerShell support requires PowerShell 5.1 to be installed on your machine. If you are Windows 7 user, you need to [install it manually](https://www.microsoft.com/en-us/download/details.aspx?id=54616) (Windows 8 and 10 includes it by default). This also means that PowerShell functionality is restricted to 5.1 version. Playnite currently doesn't support newer PowerShell Core runtime (PowerShell versions 6 and newer).
|
||||
|
||||
Execution
|
||||
---------------------
|
||||
|
||||
Scripts are executed in the following order:
|
||||
|
||||
global pre -> emulator pre -> game pre -> game post -> emulator post -> global post -> emulator exit -> game exit -> global exit
|
||||
|
||||
where:
|
||||
|
||||
- pre - before game is started.
|
||||
- post - after game is started running.
|
||||
- exit - after game stopped running.
|
||||
|
||||
If a game has installation directory set and that directory actually exists, Playnite will set current working directory of a script runtime to that installation directory.
|
||||
|
||||
All scripts share the same runtime environment for a single game session. This means that you can share data between them if you declare your variables on global scope, for example `$global:testVar = 2`.
|
||||
|
||||
> [!NOTE]
|
||||
> All scripts are executed synchronously, meaning that Playnite will wait for a script to finish and will block any other execution, including UI since the script runtime runs on main thread.
|
||||
|
||||
Startup script is an exception to mentioned execution behavior, see startup script section for more details.
|
||||
|
||||
Script variables
|
||||
---------------------
|
||||
|
||||
Playnite provides some built-in global variables that scripts can use to get more information about current game session.
|
||||
|
||||
| Variable | Description |
|
||||
| :-- | :-- |
|
||||
| PlayniteApi | Instance of [Playnite API](xref:Playnite.SDK.IPlayniteAPI). |
|
||||
| Game | [Game](xref:Playnite.SDK.Models.Game) library object for current game session. |
|
||||
| SourceAction | Custom [game action](xref:Playnite.SDK.Models.GameAction) used to start a game. |
|
||||
| SelectedRomFile | ROM file selected when running a game with multiple ROMs assigned. |
|
||||
|
||||
Startup script
|
||||
---------------------
|
||||
|
||||
If you need more complex startup and game tracking procedure other then just starting an executable, or default session tracking doesn't work for a specific game, then you can start and manage game session using a script. This is currently available to emulators (custom profiles) and games.
|
||||
|
||||
The script should keep running while you want Playnite to detect the game as running. Once the script finishes with execution, Playnite considers the game to stop running and will record game session length based on how long the script was running (adding that time to overall game play time).
|
||||
|
||||
> [!NOTE]
|
||||
> Startup scripts run in a separate script runtime and thread compared to other game scripts. Therefore you can't share data with other game/global scripts and you can't directly call any code that must be run on main thread (most UI things)!
|
||||
>
|
||||
> Breaking exceptions from startup script are not propagated to UI via error message (like for other game/global scripts) and are only logged into Playnite's log file.
|
||||
|
||||
### Startup script example
|
||||
|
||||
```powershell
|
||||
$process = [System.Diagnostics.Process]::Start("game.exe")
|
||||
$process.WaitForExit()
|
||||
$process.Dispose()
|
||||
```
|
||||
|
||||
### Reacting to tracking cancellation
|
||||
|
||||
You can use `$CancelToken.IsCancellationRequested` to detect if user cancelled game session manually from Playnite. When cancellation is initiated, Playnite sets mentioned property to `true` and gives the script 10 seconds to exit gracefully. If the script fails to exit in that time, script's runtime is killed.
|
||||
|
||||
```powershell
|
||||
# WaitForExit() is synchronous check so it can't be used if you want to support session cancellation
|
||||
$process = [System.Diagnostics.Process]::Start("game.exe")
|
||||
while ($true)
|
||||
{
|
||||
# Check if user cancelled game session
|
||||
if ($CancelToken.IsCancellationRequested)
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
# Check if process is still running
|
||||
if (!(Get-Process -Name "game" -EA 0))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
# Sleep for a while to not waste CPU
|
||||
Start-Sleep -s 1
|
||||
}
|
||||
|
||||
$process.Dispose()
|
||||
```
|
||||
|
||||
### Startup script variables
|
||||
|
||||
| Variable | Description |
|
||||
| :-- | :-- |
|
||||
| PlayniteApi | Instance of [Playnite API](xref:Playnite.SDK.IPlayniteAPI). |
|
||||
| Game | [Game](xref:Playnite.SDK.Models.Game) library object for current game session. |
|
||||
| IsPlayAction | Indicates whether an action was started as play action. |
|
||||
|
||||
Examples
|
||||
---------------------
|
||||
|
||||
### Starting additional application(s) before game starts and killing it after game exits.
|
||||
|
||||
* Edit game and go to `Scripts` tab
|
||||
* Change runtime to `PowerShell`
|
||||
* Set first script to start your application using [Start-Process](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-5.1) cmdlet
|
||||
|
||||
```powershell
|
||||
Start-Process "c:\somepath\someapp.exe" "-some arguments"
|
||||
```
|
||||
|
||||
* Set second script to kill the application using [Stop-Process]https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/stop-process?view=powershell-5.1) cmdlet
|
||||
|
||||
```powershell
|
||||
Stop-Process -Name "someapp"
|
||||
```
|
||||
|
||||
* If the application requires elevated rights to start then you need to start Playnite as admin too, otherwise the `Stop-Process` will fail due to insufficient privileges.
|
||||
* If you want to start application minimized and application doesn't have native support for it then add `-WindowStyle` argument.
|
||||
|
||||
```powershell
|
||||
Start-Process "c:\somepath\someapp.exe" "-some arguments" -WindowStyle Minimized
|
||||
```
|
||||
|
||||
Troubleshooting
|
||||
---------------------
|
||||
|
||||
### Application doesn't start
|
||||
|
||||
Some applications won't work properly (or even start) when started using working directory outside of their application director. In that case you need to use `-WorkingDirectory` parameter and specify working directory manually.
|
||||
|
||||
### Can't shutdown process
|
||||
|
||||
You won't be able to use `Stop-Process` on processes that are started with elevated rights. In that case, you need to use WMI to shutdown a process:
|
||||
|
||||
```powershell
|
||||
(Get-WmiObject -Class Win32_Process -Filter "name = 'someapp.exe'").Terminate()
|
||||
```
|
||||
### Exceptions related to directory not being found
|
||||
|
||||
Paths (and strings in general) in various places in PowerShell are handled not as literal strings, but as strings with wildcard patterns. This has unfortunate issue if specific command doesn't allow you to pass literal string via a specific argument (for example `-LiteralPath`) or has an option to disable wildcard parsing.
|
||||
|
||||
This can cause issues if game's installation path contains wildcard pattern characters. For example game installed in `d:\[test] game name\` will cause issues to `Start-Process` cmdlet, because of `[` and `]` pattern characters. This is because Playnite sets script runtime's working directory to game's installation path and Start-Process tries to parse it before launching a program.
|
||||
|
||||
Solution is to either use literal path arguments or use different cmdlet or .NET classes directly. For example to start a process:
|
||||
|
||||
```powershell
|
||||
# Instead of:
|
||||
Start-Process "game.exe"
|
||||
|
||||
# call .NET class directly:
|
||||
[System.Diagnostics.Process]::Start("game.exe")
|
||||
```
|
||||
|
||||
Note: This issue has been fixed in newer versions of PowerShell, but since Playnite has to use older version (5.1) until we switch to newer .NET runtime, you may encounter this issue.
|
||||
@ -1,28 +0,0 @@
|
||||
Game variables
|
||||
=====================
|
||||
|
||||
Following is the list of game variables that can be used in various places, specifically in:
|
||||
|
||||
- game links
|
||||
- emulator configuration fields
|
||||
- game action fields
|
||||
|
||||
To use a variable, encapsulate it with curly brackets in a string, for example:
|
||||
|
||||
`some string {GameId} test`
|
||||
|
||||
|Variable|Description|
|
||||
| ------------- | ------------- |
|
||||
|InstallDir|Game installation directory|
|
||||
|InstallDirName|Name of installation folder
|
||||
|ImagePath|Game ISO/ROM path if set|
|
||||
|ImageName|Game ISO/ROM file name|
|
||||
|ImageNameNoExt|Game ISO/ROM file name without extension|
|
||||
|PlayniteDir|Playnite's installation directory|
|
||||
|Name|Game name |
|
||||
|Platform|Game's platform |
|
||||
|GameId|Game's ID |
|
||||
|DatabaseId|Game's database ID |
|
||||
|PluginId|Game's library plugin ID |
|
||||
|Version|Game version|
|
||||
|EmulatorDir|Emulator's installation directory|
|
||||
@ -1,34 +0,0 @@
|
||||
Library manager
|
||||
=====================
|
||||
|
||||
Introduction
|
||||
---------------------
|
||||
|
||||
Library manager can be accessed from main menu `Library -> Library manager` sub menu. I can be used to manage various game fields shared between games.
|
||||
|
||||
Platforms
|
||||
---------------------
|
||||
|
||||
### Custom images
|
||||
|
||||
Icon, Cover and Background images assigned to a platform can be used as a replacement images for games that don't have any of those images assigned. Whether platform images will be used can be controlled via application settings in `Appearance -> Advanced` section via `Missing game * source` options.
|
||||
|
||||
### Platform specification
|
||||
|
||||
Platform specification fields allow you indicate to Playnite how to treat your specific platform based on internal list of built-in platforms. Setting this to correct value will improve field assignments from various automatic actions like game import or metadata import and will also prevent creation of potential platform duplicates.
|
||||
|
||||
If you don't see a platform on the list of platform specifications, please [open new GitHub issue](https://github.com/JosefNemec/Playnite/issues) for the platform to be added.
|
||||
|
||||
Regions
|
||||
---------------------
|
||||
|
||||
Similar to platform specifications, you can assign region specification from built-in list of regions to improve automatic game and metadata imports.
|
||||
|
||||
Completion statuses
|
||||
---------------------
|
||||
|
||||
Completion statuses view offers additional settings used to configure how Playnite handles specific statuses.
|
||||
|
||||
`Default status assigned to newly added games`: specify which status will be assigned to newly imported imported games with no play time recorded yet.
|
||||
|
||||
`Status assigned to games played for the first time`: specify which status will be assigned to games played for the first time.
|
||||
@ -1,17 +0,0 @@
|
||||
- name: Application arguments
|
||||
href: cmdlineArguments.md
|
||||
|
||||
- name: Game variables
|
||||
href: gameVariables.md
|
||||
|
||||
- name: Game scripts
|
||||
href: gameScripts.md
|
||||
|
||||
- name: Emulator support
|
||||
href: emulators.md
|
||||
|
||||
- name: Game actions
|
||||
href: gameActions.md
|
||||
|
||||
- name: Library manager
|
||||
href: libraryManager.md
|
||||
@ -1,17 +0,0 @@
|
||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||
|
||||
<h1 id="{{id}}" data-uid="{{uid}}" class="text-break">{{>partials/title}}</h1>
|
||||
<div class="markdown level0 summary">{{{summary}}}</div>
|
||||
<div class="markdown level0 conceptual">{{{conceptual}}}</div>
|
||||
{{#inClass}}
|
||||
<h6><strong>{{__global.namespace}}</strong>: {{{namespace.specName.0.value}}}</h6>
|
||||
{{#remarks}}
|
||||
<h5 id="{{id}}_remarks"><strong>{{__global.remarks}}</strong></h5>
|
||||
<div class="markdown level0 remarks">{{{remarks}}}</div>
|
||||
{{/remarks}}
|
||||
{{#example.0}}
|
||||
<h5 id="{{id}}_examples"><strong>{{__global.examples}}</strong></h5>
|
||||
{{/example.0}}
|
||||
{{#example}}
|
||||
{{{.}}}
|
||||
{{/example}}
|
||||
246
doc/templates/playnite/partials/class.tmpl.partial
vendored
246
doc/templates/playnite/partials/class.tmpl.partial
vendored
@ -1,246 +0,0 @@
|
||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||
{{>partials/class.header}}
|
||||
{{#inheritedMembers.0}}
|
||||
<div class="inheritance">
|
||||
<h3>Inherited members</h3>
|
||||
{{/inheritedMembers.0}}
|
||||
{{#inheritedMembers}}
|
||||
<div class="level{{index}}">
|
||||
{{#definition}}
|
||||
<xref href="{{definition}}" fullName="{{fullName.0.value}}" name="{{name.0.value}}"/>
|
||||
{{/definition}}
|
||||
{{^definition}}
|
||||
<xref href="{{uid}}" fullName="{{fullName.0.value}}" name="{{name.0.value}}"/>
|
||||
{{/definition}}
|
||||
</div>
|
||||
{{/inheritedMembers}}
|
||||
{{#inheritedMembers.0}}
|
||||
</div>
|
||||
{{/inheritedMembers.0}}
|
||||
{{#children}}
|
||||
<h3 id="{{id}}">{{>partials/classSubtitle}}</h3>
|
||||
{{#children}}
|
||||
{{^_disableContribution}}
|
||||
{{#docurl}}
|
||||
<span class="small pull-right mobile-hide">
|
||||
<span class="divider">|</span>
|
||||
<a href="{{docurl}}">{{__global.improveThisDoc}}</a>
|
||||
</span>{{/docurl}}
|
||||
{{#sourceurl}}
|
||||
<span class="small pull-right mobile-hide">
|
||||
<a href="{{sourceurl}}">{{__global.viewSource}}</a>
|
||||
</span>{{/sourceurl}}
|
||||
{{/_disableContribution}}
|
||||
{{#overload}}
|
||||
<a id="{{id}}" data-uid="{{uid}}"></a>
|
||||
{{/overload}}
|
||||
<h4 id="{{id}}" data-uid="{{uid}}">{{name.0.value}}</h4>
|
||||
<div class="markdown level1 summary">{{{summary}}}</div>
|
||||
<div class="markdown level1 conceptual">{{{conceptual}}}</div>
|
||||
{{#syntax}}
|
||||
{{#parameters.0}}
|
||||
<h5 class="parameters">{{__global.parameters}}</h5>
|
||||
<table class="table table-bordered table-striped table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{__global.type}}</th>
|
||||
<th>{{__global.name}}</th>
|
||||
<th>{{__global.description}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{/parameters.0}}
|
||||
{{#parameters}}
|
||||
<tr>
|
||||
<td>{{{type.specName.0.value}}}</td>
|
||||
<td><span class="parametername">{{{id}}}</span></td>
|
||||
<td>{{{description}}}</td>
|
||||
</tr>
|
||||
{{/parameters}}
|
||||
{{#parameters.0}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/parameters.0}}
|
||||
{{#return}}
|
||||
<h5 class="returns">{{__global.returns}}</h5>
|
||||
<table class="table table-bordered table-striped table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{__global.type}}</th>
|
||||
<th>{{__global.description}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{{type.specName.0.value}}}</td>
|
||||
<td>{{{description}}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{{/return}}
|
||||
{{#typeParameters.0}}
|
||||
<h5 class="typeParameters">{{__global.typeParameters}}</h5>
|
||||
<table class="table table-bordered table-striped table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{__global.name}}</th>
|
||||
<th>{{__global.description}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{/typeParameters.0}}
|
||||
{{#typeParameters}}
|
||||
<tr>
|
||||
<td><span class="parametername">{{{id}}}</span></td>
|
||||
<td>{{{description}}}</td>
|
||||
</tr>
|
||||
{{/typeParameters}}
|
||||
{{#typeParameters.0}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/typeParameters.0}}
|
||||
{{#fieldValue}}
|
||||
<h5 class="fieldValue">{{__global.fieldValue}}</h5>
|
||||
<table class="table table-bordered table-striped table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{__global.type}}</th>
|
||||
<th>{{__global.description}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{{type.specName.0.value}}}</td>
|
||||
<td>{{{description}}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{{/fieldValue}}
|
||||
{{#propertyValue}}
|
||||
<h5 class="propertyValue">{{__global.propertyValue}}</h5>
|
||||
<table class="table table-bordered table-striped table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{__global.type}}</th>
|
||||
<th>{{__global.description}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{{type.specName.0.value}}}</td>
|
||||
<td>{{{description}}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{{/propertyValue}}
|
||||
{{#eventType}}
|
||||
<h5 class="eventType">{{__global.eventType}}</h5>
|
||||
<table class="table table-bordered table-striped table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{__global.type}}</th>
|
||||
<th>{{__global.description}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{{type.specName.0.value}}}</td>
|
||||
<td>{{{description}}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{{/eventType}}
|
||||
{{/syntax}}
|
||||
{{#overridden}}
|
||||
<h5 class="overrides">{{__global.overrides}}</h5>
|
||||
<div><xref uid="{{uid}}" altProperty="fullName" displayProperty="nameWithType"/></div>
|
||||
{{/overridden}}
|
||||
{{#remarks}}
|
||||
<h5 id="{{id}}_remarks">{{__global.remarks}}</h5>
|
||||
<div class="markdown level1 remarks">{{{remarks}}}</div>
|
||||
{{/remarks}}
|
||||
{{#example.0}}
|
||||
<h5 id="{{id}}_examples">{{__global.examples}}</h5>
|
||||
{{/example.0}}
|
||||
{{#example}}
|
||||
{{{.}}}
|
||||
{{/example}}
|
||||
{{#exceptions.0}}
|
||||
<h5 class="exceptions">{{__global.exceptions}}</h5>
|
||||
<table class="table table-bordered table-striped table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{__global.type}}</th>
|
||||
<th>{{__global.condition}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{/exceptions.0}}
|
||||
{{#exceptions}}
|
||||
<tr>
|
||||
<td>{{{type.specName.0.value}}}</td>
|
||||
<td>{{{description}}}</td>
|
||||
</tr>
|
||||
{{/exceptions}}
|
||||
{{#exceptions.0}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/exceptions.0}}
|
||||
{{#seealso.0}}
|
||||
<h5 id="{{id}}_seealso">{{__global.seealso}}</h5>
|
||||
<div class="seealso">
|
||||
{{/seealso.0}}
|
||||
{{#seealso}}
|
||||
{{#isCref}}
|
||||
<div>{{{type.specName.0.value}}}</div>
|
||||
{{/isCref}}
|
||||
{{^isCref}}
|
||||
<div>{{{url}}}</div>
|
||||
{{/isCref}}
|
||||
{{/seealso}}
|
||||
{{#seealso.0}}
|
||||
</div>
|
||||
{{/seealso.0}}
|
||||
{{/children}}
|
||||
{{/children}}
|
||||
{{#implements.0}}
|
||||
<h3 id="implements">{{__global.implements}}</h3>
|
||||
{{/implements.0}}
|
||||
{{#implements}}
|
||||
<div>
|
||||
{{#definition}}
|
||||
<xref uid="{{definition}}" altProperty="fullName" displayProperty="nameWithType"/>
|
||||
{{/definition}}
|
||||
{{^definition}}
|
||||
<xref uid="{{uid}}" altProperty="fullName" displayProperty="nameWithType"/>
|
||||
{{/definition}}
|
||||
</div>
|
||||
{{/implements}}
|
||||
{{#extensionMethods.0}}
|
||||
<h3 id="extensionmethods">{{__global.extensionMethods}}</h3>
|
||||
{{/extensionMethods.0}}
|
||||
{{#extensionMethods}}
|
||||
<div>
|
||||
{{#definition}}
|
||||
<xref uid="{{definition}}" altProperty="fullName" displayProperty="nameWithType"/>
|
||||
{{/definition}}
|
||||
{{^definition}}
|
||||
<xref uid="{{uid}}" altProperty="fullName" displayProperty="nameWithType"/>
|
||||
{{/definition}}
|
||||
</div>
|
||||
{{/extensionMethods}}
|
||||
{{#seealso.0}}
|
||||
<h3 id="seealso">{{__global.seealso}}</h3>
|
||||
<div class="seealso">
|
||||
{{/seealso.0}}
|
||||
{{#seealso}}
|
||||
{{#isCref}}
|
||||
<div>{{{type.specName.0.value}}}</div>
|
||||
{{/isCref}}
|
||||
{{^isCref}}
|
||||
<div>{{{url}}}</div>
|
||||
{{/isCref}}
|
||||
{{/seealso}}
|
||||
{{#seealso.0}}
|
||||
</div>
|
||||
{{/seealso.0}}
|
||||
@ -1,28 +0,0 @@
|
||||
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
|
||||
{{#inConstructor}}
|
||||
{{__global.constructorsInSubtitle}}
|
||||
{{/inConstructor}}
|
||||
{{#inField}}
|
||||
{{__global.fieldsInSubtitle}}
|
||||
{{/inField}}
|
||||
{{#inProperty}}
|
||||
{{__global.propertiesInSubtitle}}
|
||||
{{/inProperty}}
|
||||
{{#inMethod}}
|
||||
{{__global.methodsInSubtitle}}
|
||||
{{/inMethod}}
|
||||
{{#inEvent}}
|
||||
{{__global.eventsInSubtitle}}
|
||||
{{/inEvent}}
|
||||
{{#inOperator}}
|
||||
{{__global.operatorsInSubtitle}}
|
||||
{{/inOperator}}
|
||||
{{#inEii}}
|
||||
{{__global.eiisInSubtitle}}
|
||||
{{/inEii}}
|
||||
{{#inFunction}}
|
||||
{{__global.functionsInSubtitle}}
|
||||
{{/inFunction}}
|
||||
{{#inMember}}
|
||||
{{__global.membersInSubtitle}}
|
||||
{{/inMember}}
|
||||
29
doc/templates/playnite/styles/main.css
vendored
29
doc/templates/playnite/styles/main.css
vendored
@ -1,29 +0,0 @@
|
||||
@media (min-width:992px){.container{width:970px}
|
||||
}
|
||||
@media (min-width:1350px){.container{width:1300px}
|
||||
}
|
||||
|
||||
.tabGroup section[role="tabpanel"] > .codeHeader, .tabGroup section[role="tabpanel"] > pre
|
||||
{
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
.tabGroup section[role="tabpanel"] > :first-child
|
||||
{
|
||||
margin-top: -16px;
|
||||
}
|
||||
|
||||
.tabGroup {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
color: #333;
|
||||
background-color: #d9edf7;
|
||||
border-color: #bce8f1;
|
||||
}
|
||||
|
||||
article h4 {
|
||||
border-bottom: 0px;
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
- name: Tutorials
|
||||
href: tutorials/
|
||||
- name: Manual
|
||||
href: manual/
|
||||
- name: API Documentation
|
||||
href: api/
|
||||
homepage: api/index.md
|
||||
@ -1,113 +0,0 @@
|
||||
Custom UI Integration
|
||||
=====================
|
||||
|
||||
Introduction
|
||||
---------------------
|
||||
|
||||
Extensions can expose custom UI elements for themes to integrate, this requires support by both an extension and a theme. For theme implementation part, see [this page](../themes/extensionIntegration.md).
|
||||
|
||||
Implementation
|
||||
---------------------
|
||||
|
||||
### User Control implementation
|
||||
|
||||
1) Add new standard WPF UserControl into your project.
|
||||
2) Change base class from `UserControl` to `PluginUserControl`
|
||||
|
||||
You should end up with something like this:
|
||||
|
||||
```xml
|
||||
<PluginUserControl x:Class="TestPlugin.TestPluginUserControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid>
|
||||
</Grid>
|
||||
</PluginUserControl>
|
||||
```
|
||||
|
||||
```csharp
|
||||
public partial class TestPluginUserControl : PluginUserControl
|
||||
{
|
||||
public TestPluginUserControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Registering custom control
|
||||
|
||||
For new control to be recognized by Playnite API and themes call [AddCustomElementSupport](xref:Playnite.SDK.Plugins.Plugin.AddCustomElementSupport(Playnite.SDK.Plugins.AddCustomElementSupportArgs)) method in plugin's constructor.
|
||||
|
||||
`AddCustomElementSupportArgs` contains several arguments:
|
||||
|
||||
|Property|Description|
|
||||
|:---|:---|
|
||||
|ElementList| List of element names supported by the plugin. |
|
||||
|SourceName| Plugin source name for element name references and settings bindings. |
|
||||
|
||||
Following example will allow themes to reference plugin controls by `TestPlugin_TestUserControl1` and `TestPlugin_TestUserControl2` names:
|
||||
|
||||
```csharp
|
||||
AddCustomElementSupport(new AddCustomElementSupportArgs
|
||||
{
|
||||
ElementList = new List<string> { "TestUserControl1", "TestUserControl2" },
|
||||
SourceName = "TestPlugin"
|
||||
});
|
||||
```
|
||||
|
||||
Lastly, override [GetGameViewControl](xref:Playnite.SDK.Plugins.Plugin.GetGameViewControl(Playnite.SDK.Plugins.GetGameViewControlArgs)) method. The method is called when theme view template is initialized and plugin control should be "injected" into the view.
|
||||
|
||||
Example:
|
||||
```csharp
|
||||
public override Control GetGameViewControl(GetGameViewControlArgs args)
|
||||
{
|
||||
if (args.Name == "TestUserControl")
|
||||
{
|
||||
return new TestPluginUserControl();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
### Handling data context
|
||||
|
||||
Data of currently bound game object can be accessed via PluginUserControl's `GameContext` property. If you want to react to data context changes, you can override [GameContextChanged](xref:Playnite.SDK.Controls.PluginUserControl.GameContextChanged(Playnite.SDK.Models.Game,Playnite.SDK.Models.Game)) method.
|
||||
|
||||
Exposing extension settings
|
||||
---------------------
|
||||
|
||||
You can provide easy way for themes to reference extension settings by calling [AddSettingsSupport](xref:Playnite.SDK.Plugins.Plugin.AddSettingsSupport(Playnite.SDK.Plugins.AddSettingsSupportArgs)) method in plugin's constructor, similarly to how custom element support is done.
|
||||
|
||||
`AddSettingsSupport` contains several arguments:
|
||||
|
||||
|Property|Description|
|
||||
|:---|:---|
|
||||
|SourceName| Plugin source name for element name references and settings bindings. |
|
||||
|SettingsRoot| Binding root path relative to a plugin object instance. |
|
||||
|
||||
`SettingsRoot` must be relative binding path to the plugin class. For example, if your plugin class stores settings in `Settings` property, then SettingsRoot should be set to just "Settings". If you want themes to dynamically react to settings changes, then you need to implement `INotifyPropertyChanged` on your settings object.
|
||||
|
||||
Example:
|
||||
```csharp
|
||||
AddSettingsSupport(new AddSettingsSupportArgs
|
||||
{
|
||||
SourceName = "TestPlugin",
|
||||
SettingsRoot = $"binding.path.relative.to.plugin.object"
|
||||
});
|
||||
```
|
||||
|
||||
Themes can then reference settings via `PluginSettings` markup. See [theme integration page](../themes/extensionIntegration.md#extension-settings) for more details.
|
||||
|
||||
Theme integration
|
||||
---------------------
|
||||
|
||||
See [theme integration page](../themes/extensionIntegration.md) for more details.
|
||||
|
||||
As an extension developer you should provide following information to theme developer:
|
||||
|
||||
`Source name`: For both general UI integration and settings integration.
|
||||
`Element list`: List of element names that you extension exposes and themes can integrate.
|
||||
`Settings list`: If your extension exposes settings that can be used by themes.
|
||||
`Addon id`: Addon id used in extension manifest, for theme developers to be able to [detect](../themes/extensionIntegration.md#detecting-if-an-extension-is-installed) if your extension is installed or not.
|
||||
@ -1,16 +0,0 @@
|
||||
Script data directory
|
||||
=====================
|
||||
|
||||
Extensions should store any generated data in a designated extension data directory instead of its installation directory, because installation directory gets purged during extension installation or update.
|
||||
|
||||
Scripts
|
||||
---------------------
|
||||
|
||||
To get script data directory, use `CurrentExtensionDataPath` global variable.
|
||||
|
||||
To get installation directory of currently running script, use `CurrentExtensionInstallPath` global variable. In PowerShell scripts you may also use the standard `$PSScriptRoot` variable.
|
||||
|
||||
Plugins
|
||||
---------------------
|
||||
|
||||
To get the directory, call [GetPluginUserDataPath](xref:Playnite.SDK.Plugins.Plugin.GetPluginUserDataPath) method. The method returns full path designated to to a specific plugin. The same directory is used to store plugin [settings](pluginSettings.md).
|
||||
@ -1,71 +0,0 @@
|
||||
Reacting to events
|
||||
=====================
|
||||
|
||||
Introduction
|
||||
---------------------
|
||||
|
||||
Playnite's API allows extensions to react to various events, like when a game is started or installed.
|
||||
|
||||
Available Events
|
||||
---------------------
|
||||
|
||||
| Name | Event | Passed Arguments |
|
||||
| --- | --- | --- |
|
||||
| OnGameStarting | Before game is started. | [OnGameStartingEventArgs](xref:Playnite.SDK.Events.OnGameStartingEventArgs) |
|
||||
| OnGameStarted | Game started running. | [OnGameStartedEventArgs](xref:Playnite.SDK.Events.OnGameStartedEventArgs) |
|
||||
| OnGameStopped | Game stopped running. | [OnGameStoppedEventArgs](xref:Playnite.SDK.Events.OnGameStoppedEventArgs) |
|
||||
| OnGameInstalled | Game is installed. | [OnGameInstalledEventArgs](xref:Playnite.SDK.Events.OnGameInstalledEventArgs) |
|
||||
| OnGameUninstalled | Game is uninstalled. | [OnGameUninstalledEventArgs](xref:Playnite.SDK.Events.OnGameUninstalledEventArgs) |
|
||||
| OnGameSelected | Game selection changed. | [OnGameSelectedEventArgs](xref:Playnite.SDK.Events.OnGameSelectedEventArgs) |
|
||||
| OnApplicationStarted | Playnite was started. | [OnApplicationStartedEventArgs](xref:Playnite.SDK.Events.OnApplicationStartedEventArgs) |
|
||||
| OnApplicationStopped | Playnite is shutting down. | [OnApplicationStoppedEventArgs](xref:Playnite.SDK.Events.OnApplicationStoppedEventArgs) |
|
||||
| OnLibraryUpdated | Library was updated. | [OnLibraryUpdatedEventArgs](xref:Playnite.SDK.Events.OnLibraryUpdatedEventArgs) |
|
||||
|
||||
Example - Handling start/stop events
|
||||
---------------------
|
||||
|
||||
### Game Starting
|
||||
|
||||
Following example writes name of currently playing game into a text file.
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
# To have a code executed on a specific event, override selected event method in your plugin.
|
||||
public override void OnGameStarted(OnGameStartedEventArgs args)
|
||||
{
|
||||
logger.Info($"Game started: {args.Game.Name}");
|
||||
}
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
# To have a code executed on a specific event, define script function with selected name and export it from your PowerShell extension module.
|
||||
function OnGameStarted()
|
||||
{
|
||||
param($args)
|
||||
$ags.Game.Name | Out-File "RunningGame.txt"
|
||||
}
|
||||
```
|
||||
***
|
||||
|
||||
### Game Stopped
|
||||
|
||||
This example writes name of game that stopped running and the time game was running for into a text file.
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
public override void OnGameStopped(OnGameStoppedEventArgs args)
|
||||
{
|
||||
logger.Info($"{args.Game.Name} was running for {args.ElapsedSeconds} seconds");
|
||||
}
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
function OnGameStopped()
|
||||
{
|
||||
param($args)
|
||||
"$($args.Game.Name) was running for $($args.ElapsedSeconds) seconds" | Out-File "StoppedGame.txt"
|
||||
}
|
||||
```
|
||||
***
|
||||
@ -1,21 +0,0 @@
|
||||
Working With Dynamic Variables
|
||||
=====================
|
||||
|
||||
Basics
|
||||
---------------------
|
||||
|
||||
Some game fields support user of dynamic variables. For example game action can have working directory pointing to `{InstallDir}`, Playnite then inserts game's installation directory when executing action. Playnite API provides [ExpandGameVariables](xref:Playnite.SDK.IPlayniteAPI.ExpandGameVariables(Playnite.SDK.Models.Game,System.String)) method which resolves these variables from any string.
|
||||
|
||||
Full list of variables is available on [here](../../manual/gameVariables.md).
|
||||
|
||||
Example
|
||||
---------------------
|
||||
|
||||
Lets say we have a game which has Play action with `Path` set to `{InstallDir}\app.exe` and `InstallDirectory` to `c:\appdir\`. To get full path `c:\appdir\app.exe` use [ExpandGameVariables](xref:Playnite.SDK.IPlayniteAPI.ExpandGameVariables(Playnite.SDK.Models.Game,System.String)) method.
|
||||
|
||||
```powershell
|
||||
$PlayniteApi.ExpandGameVariables($game, $game.PlayTask.Path)
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> You don't have to check if the string contains any dynamic variables to know whether to use `ExpandGameVariables` or not. If input string doesn't contain any dynamic variables it won't be modified in any way and `ExpandGameVariables` just returns it untouched.
|
||||
@ -1,52 +0,0 @@
|
||||
Extensions Manifest
|
||||
=====================
|
||||
|
||||
Extension manifest files are used by Playnite to load extensions and display basic information to user on extension settings dialog. Manifest files are mandatory and extension won't be loaded unless valid manifest file is present inside extension directory under `extension.yaml` file name.
|
||||
|
||||
Format
|
||||
---------------------
|
||||
|
||||
Manifest is YAML formatted file with following properties:
|
||||
|
||||
| Property | Description |
|
||||
| -- | -- |
|
||||
| Id | Unique string identifier for the extension. Must not be shared with any other extension. |
|
||||
| Name | Extension name. |
|
||||
| Author | Extension author. |
|
||||
| Version | Extension version, must be a valid [.NET version string](https://docs.microsoft.com/en-us/dotnet/api/system.version). |
|
||||
| Module | File name of assembly `*.dll` file for plugins, `*.psm1` or `*.psd1` file for scripts. |
|
||||
| Type | Extension type, available values are: `Script`, `GenericPlugin`, `GameLibrary`, `MetadataProvider`. |
|
||||
| Icon | Optional relative file name of extension icon. |
|
||||
| Links | Optional list of links (extension website, changelog etc.) |
|
||||
|
||||
Examples
|
||||
---------------------
|
||||
|
||||
**Example of script extension:**
|
||||
|
||||
```yaml
|
||||
Id: LibraryExporter_Playnite_Script
|
||||
Name: Library Exporter
|
||||
Author: Playnite
|
||||
Version: 1.0
|
||||
Module: LibraryExporter.psm1
|
||||
Type: Script
|
||||
Links:
|
||||
- Name: Website
|
||||
Url: https://some.website.nowhere
|
||||
```
|
||||
|
||||
**Example of library plugin:**
|
||||
|
||||
```yaml
|
||||
Id: SomeLibraryPlugin_Playnite_Plugin
|
||||
Name: Some Library Plugin
|
||||
Author: Playnite
|
||||
Version: 1.0
|
||||
Module: SomeLibraryPlugin.dll
|
||||
Type: GameLibrary
|
||||
Icon: pluginicon.png
|
||||
Links:
|
||||
- Name: Website
|
||||
Url: https://some.website.nowhere
|
||||
```
|
||||
@ -1,45 +0,0 @@
|
||||
Game actions
|
||||
=====================
|
||||
|
||||
Introduction
|
||||
---------------------
|
||||
|
||||
Extensions can "inject" game actions dynamically when a game is started rather then assigning them permanently to a game. How this works is that when starting a game, Playnite asks all installed plugins if they know how to handle specific operation for a selected game and if they return controller for that specific action, Playnite will give user an option to use implementation from those plugins.
|
||||
|
||||
> [!NOTE]
|
||||
> Make sure you are returning actions only for games your plugin is able to handle properly. For example by checking if game's source `PluginId` matches yours if you are implementing a controller for a library plugin. You should not be returning any controllers for a game that you can't provide support for.
|
||||
|
||||
Play actions
|
||||
---------------------
|
||||
|
||||
Play actions control how a game is started and are also responsible for play time tracking. To implement play action handling, override `GetPlayActions` method from your plugin and return [PlayController](xref:Playnite.SDK.Plugins.PlayController) object implementing game startup functionality.
|
||||
|
||||
In you play controller: call `InvokeOnStarted` after the game is started and `InvokeOnStopped` when the game stops running. `InvokeOnStopped` should provide information about last game session, mainly how long the session lasted, for Playnite to record play time properly.
|
||||
|
||||
"Automatic" play actions
|
||||
---------------------
|
||||
|
||||
If game startup procedure for your plugin doesn't require any special handling, you can use [AutomaticPlayController](xref:Playnite.SDK.Plugins.AutomaticPlayController) to simplify play action controller implementation. `AutomaticPlayController` mirrors functionality of manual play action configuration you can assign via Playnite UI, it provides the same fields and functionality.
|
||||
|
||||
```csharp
|
||||
public override IEnumerable<PlayController> GetPlayActions(GetPlayActionsArgs args)
|
||||
{
|
||||
yield return new AutomaticPlayController(args.Game)
|
||||
{
|
||||
Type = GenericPlayActionType.File,
|
||||
TrackingMode = TrackingMode.Process,
|
||||
Name = "Notepad",
|
||||
Path = "notepad.exe"
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Install an uninstall actions
|
||||
---------------------
|
||||
|
||||
Similar to how Play controllers are implemented, override `GetInstallActions` and/or `GetUninstallActions` methods. Install controllers should provide [GameInstallationData](xref:Playnite.SDK.Plugins.GameInstallationData) when calling `InvokeOnInstalled` for installation status to be set properly.
|
||||
|
||||
Examples
|
||||
---------------------
|
||||
|
||||
You can check [built-in Playnite extensions](https://github.com/JosefNemec/PlayniteExtensions) for various examples of controller implementations.
|
||||
@ -1,77 +0,0 @@
|
||||
Generic Plugins
|
||||
=====================
|
||||
|
||||
To implement generic plugin:
|
||||
|
||||
* Read the introduction to [extensions](intro.md) and [plugins](plugins.md).
|
||||
* Create new public class inheriting from [Plugin](xref:Playnite.SDK.Plugins.Plugin) abstract class.
|
||||
* Add implementation for mandatory abstract members.
|
||||
|
||||
Mandatory members
|
||||
---------------------
|
||||
|
||||
| Member | Description |
|
||||
| -- | -- |
|
||||
| Id | Unique plugin id. |
|
||||
|
||||
Optional members
|
||||
---------------------
|
||||
|
||||
You can implement additional functionality by overriding virtual methods from [Plugin](xref:Playnite.SDK.Plugins.Plugin) base class.
|
||||
|
||||
Example plugin
|
||||
---------------------
|
||||
|
||||
```csharp
|
||||
public class TestPlugin : Plugin
|
||||
{
|
||||
private ILogger logger;
|
||||
|
||||
public override Guid Id { get; } = Guid.Parse("D51194CD-AA44-47A0-8B89-D1FD544DD9C9");
|
||||
|
||||
public TestPlugin(IPlayniteAPI api) : base(api)
|
||||
{
|
||||
logger = api.CreateLogger();
|
||||
}
|
||||
|
||||
public override void OnGameInstalled(Game game)
|
||||
{
|
||||
// Add code to be executed when game is finished installing.
|
||||
}
|
||||
|
||||
public override void OnGameStarted(Game game)
|
||||
{
|
||||
// Add code to be executed when game is started running.
|
||||
}
|
||||
|
||||
public override void OnGameStarting(Game game)
|
||||
{
|
||||
// Add code to be executed when game is preparing to be started.
|
||||
}
|
||||
|
||||
public override void OnGameStopped(Game game, long elapsedSeconds)
|
||||
{
|
||||
// Add code to be executed when game is preparing to be started.
|
||||
}
|
||||
|
||||
public override void OnGameUninstalled(Game game)
|
||||
{
|
||||
// Add code to be executed when game is uninstalled.
|
||||
}
|
||||
|
||||
public override void OnApplicationStarted()
|
||||
{
|
||||
// Add code to be execute when Playnite is initialized.
|
||||
}
|
||||
|
||||
public override void OnApplicationStopped()
|
||||
{
|
||||
// Add code to be executed when Playnite is shutting down.
|
||||
}
|
||||
|
||||
public override void OnLibraryUpdated()
|
||||
{
|
||||
// Add code to be execute when library is updated.
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -1,83 +0,0 @@
|
||||
# Introduction to Playnite extensions
|
||||
|
||||
Basics
|
||||
---------------------
|
||||
|
||||
Playnite can be extended via extensions implemented via scripts and plugins:
|
||||
|
||||
- Scripts: [PowerShell](https://docs.microsoft.com/en-us/powershell/) scripts are supported.
|
||||
- Plugins: Any .NET Framework compatible language can be used (`C#`, `VB.NET`, `F#` and others).
|
||||
|
||||
Extensions fall under several categories of extended functionality that are available based on selected implementation:
|
||||
|
||||
| Functionality | Scripts | Plugins |
|
||||
| -- | :--: | :--: |
|
||||
| Adding game and main menu entries | • | • |
|
||||
| Reacting to game events | • | • |
|
||||
| Adding new UI elements | | • |
|
||||
| Injecting game actions | | • |
|
||||
| Library importer | | • |
|
||||
| Metadata provider | | • |
|
||||
|
||||
- `Adding game and main menu entries` - ability to add new executable [menu entries](menus.md) to main menu and game menu.
|
||||
- `Reacting to game events` - ability to execute code when various [game events](events.md) occur, like when game is started or stopped for example.
|
||||
- `Adding new UI elements` - ability to add new [UI elements](ui.md) to various views and panels.
|
||||
- `Injecting game actions` - gives ability to "inject" new Play, Install and Uninstall [game actions](gameActions.md) in real-time.
|
||||
- `Library importer` - provides automatic import of games from various sources. For example all currently supported external clients (Steam, GOG, Origin etc.) [are implemented](https://github.com/JosefNemec/Playnite/tree/master/source/Plugins) via this extension type.
|
||||
- `Metadata provider` - provides metadata for games in Playnite. Our default metadata provider, IGDB.com, is also [implemented as a metadata plugin](https://github.com/JosefNemec/Playnite/tree/master/source/Plugins/IGDBMetadata).
|
||||
|
||||
> [!WARNING]
|
||||
> Extension installation and update always replaces the entire extension directory completely. Meaning that any files that are not part of the installation package will be lost during installation process! It is highly recommended to store generated files in a separate extensions data folder. See [Data directories](dataDirectory.md) page to learn more about extension directories.
|
||||
|
||||
> [!NOTE]
|
||||
> There's currently very active community around theme/extension development on our [Discord server](https://discord.gg/hSFvmN6). We highly recommend joining if you plan to develop add-ons for Playnite!
|
||||
|
||||
Creating Extensions
|
||||
---------------------
|
||||
|
||||
It's highly recommended to use [Toolbox](../toolbox.md) utility to create new extensions. It will generate base directory structure and all files needed for you.
|
||||
|
||||
### 1. Directory structure and location
|
||||
|
||||
First create new extension folder inside of Playnite's `Extensions` directory. Location of `Extensions` directory differs based on Playnite's installation type:
|
||||
|
||||
- Portable version: `Extensions` folder directly inside of Playnite's installation location.
|
||||
- Installed version: `%AppData%\Playnite\Extensions` folder.
|
||||
|
||||
> [!NOTE]
|
||||
> You can load extensions from custom directories by adding them as developer plugins in Playnite's `For developers` settings menu.
|
||||
|
||||
### 2. Manifest file
|
||||
|
||||
Every extension must provide valid [manifest file](extensionsManifest.md) in order to be recognized and loaded by Playnite. Manifest is YAML formatted file called `extension.yaml` that must be stored inside of extension directory.
|
||||
|
||||
Resulting folder structure should look something like this:
|
||||
```
|
||||
├──Install directory or %AppData%\Playnite
|
||||
│ └── Extensions
|
||||
│ └── ExtensionFolder
|
||||
│ ├── extension.yaml
|
||||
│ └── scriptFileName.psm1 or pluginFileName.dll
|
||||
```
|
||||
|
||||
See manifest file [documentation page](extensionsManifest.md) for more information about manifest contents.
|
||||
|
||||
### 3. Implementing extension
|
||||
|
||||
For scripts see [scripting introduction page](scripting.md).
|
||||
|
||||
For plugins see [plugins introduction page](plugins.md).
|
||||
|
||||
Loading extensions
|
||||
---------------------
|
||||
|
||||
Extensions are loaded automatically by Playnite at every startup (unless extension is disabled via settings menu). Script can be reloaded at runtime via `Tools -> Reload Scripts` menu. Plugins can't be reloaded at runtime.
|
||||
|
||||
Distribution
|
||||
---------------------
|
||||
|
||||
Use [Toolbox](../toolbox.md#packing-extensions) utility to package an extension or a theme and distribute `.pext` or `.pthm` file to users.
|
||||
|
||||
The best place to share extensions is via [Playnite add-on database](https://github.com/JosefNemec/PlayniteAddonDatabase), submitting an add-on there will make it available in Playnite's built-in add-on browser and will also enable easy add-on installation and updates.
|
||||
|
||||
It's also recommended to submit add-on entry to official Playnite forum, specifically [add-on database](https://playnite.link/forum/forum-3.html) sub-forum.
|
||||
@ -1,151 +0,0 @@
|
||||
Working with game library
|
||||
=====================
|
||||
|
||||
Introduction
|
||||
---------------------
|
||||
Game database API allows you to access and modify game library and its objects (including platforms and emulators). Database API can be accessed via `PlayniteAPI.Database` property, which provides [IDatabaseAPI](xref:Playnite.SDK.IGameDatabaseAPI) interface.
|
||||
|
||||
Handling Games
|
||||
---------------------
|
||||
|
||||
### Getting Games
|
||||
|
||||
To get list of all games in library use [Database](xref:Playnite.SDK.IPlayniteAPI.Database) property from `IPlayniteAPI` and [Games](xref:Playnite.SDK.IGameDatabase.Games) collection.
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
foreach (var game in PlayniteApi.Database.Games)
|
||||
{
|
||||
// Do stuff with a game
|
||||
}
|
||||
|
||||
// Get a game with known Id
|
||||
var game = $PlayniteApi.Database.Games[SomeGuidId];
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
# Get all games
|
||||
$games = $PlayniteApi.Database.Games
|
||||
# Get a game with known Id
|
||||
$game = $PlayniteApi.Database.Games[$SomeGuidId]
|
||||
```
|
||||
***
|
||||
|
||||
### Adding New Game
|
||||
|
||||
To add a new game create new instance of [Game](xref:Playnite.SDK.Models.Game) class and call `Add` method from [Games](xref:Playnite.SDK.IGameDatabase.Games) collection.
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
var newGame = new Game("New Game");
|
||||
PlayniteApi.Database.Games.Add(newGame);
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
$newGame = New-Object "Playnite.SDK.Models.Game"
|
||||
$newGame.Name = "New Game"
|
||||
$PlayniteApi.Database.Games.Add($newGame)
|
||||
```
|
||||
***
|
||||
|
||||
### Changing Game Data
|
||||
|
||||
Changing properties on a `Game` object doesn't automatically update the game in Playnite's database and changes are lost with application restart. To make permanent changes game object must be updated in database manually using `Update` method from [Games](xref:Playnite.SDK.IGameDatabase.Games) collection.
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
var game = PlayniteApi.Database.Games[SomeId];
|
||||
game.Name = "Changed Name";
|
||||
PlayniteApi.Database.Games.Update(game);
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
$game = $PlayniteApi.Database.Games[$SomeId]
|
||||
$game.Name = "Changed Name"
|
||||
$PlayniteApi.Database.Games.Update($game)
|
||||
```
|
||||
***
|
||||
|
||||
### Removing Games
|
||||
|
||||
To remove game from database use `Remove` method from [Games](xref:Playnite.SDK.IGameDatabase.Games) collection.
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
PlayniteApi.Database.Games.Remove(SomeId);
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
$PlayniteApi.Database.Games.Remove($SomeId)
|
||||
```
|
||||
***
|
||||
|
||||
Handling reference fields
|
||||
---------------------
|
||||
|
||||
Some fields are only stored as references in `Game` object and can't be directly updated. For example `Series` field is a reference via `SeriesId` property, you can't directly assign new value to `Series` property (it can be only used to obtain referenced series object).
|
||||
|
||||
### Updating references
|
||||
|
||||
Every reference field has it's own collection accessible in [Database](xref:Playnite.SDK.IPlayniteAPI.Database) API object. For example all series can be accessed via [Series](xref:Playnite.SDK.IGameDatabase.Series) collection.
|
||||
|
||||
If you want to change name of the series then you will need to do it by updating series item from [Series](xref:Playnite.SDK.IGameDatabase.Series) collection. The change will be automatically propagated to all games using that series. All field collections are implemented via [IItemCollection](xref:Playnite.SDK.IItemCollection`1) meaning that the update is done via the same process like updating general game information via `Update` method on the specific collection.
|
||||
|
||||
### Adding references
|
||||
|
||||
To assign completely new series to a game:
|
||||
|
||||
- Add new series into [Series](xref:Playnite.SDK.IGameDatabase.Series) database collection.
|
||||
- Assign ID of newly added series to the game via `SeriesId` property.
|
||||
- Call Update on `Games` collection to update new `SeriesId` in database.
|
||||
|
||||
Some fields allow you to assign more items to a game. For example you can assign multiple tags to a game. In that case you need to assign [List](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1) of IDs to `TagIds` property.
|
||||
|
||||
Handling Files
|
||||
---------------------
|
||||
|
||||
All game related image files are stored in game database itself, with only reference Id being used on the game object itself (with exception of [BackgroundImage](xref:Playnite.SDK.Models.Game.BackgroundImage), which allows use of WEB URL as well). Following examples show how to handle game images using database API.
|
||||
|
||||
### Exporting Game Cover
|
||||
|
||||
Game cover images are referenced in [CoverImage](xref:Playnite.SDK.Models.Game.CoverImage) property. To save a file first get the file record by calling [GetFullFilePath](xref:Playnite.SDK.IGameDatabaseAPI.GetFullFilePath(System.String)) method. `GetFullFilePath` returns full path to a file on the disk drive.
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
var game = PlayniteApi.Database.Games[SomeId];
|
||||
var coverPath = PlayniteApi.Database.GetFullFilePath(game.CoverImage);
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
$game = $PlayniteApi.Database.Games[$SomeId]
|
||||
$coverPath = $PlayniteApi.Database.GetFullFilePath($game.CoverImage)
|
||||
```
|
||||
***
|
||||
|
||||
### Changing Cover Image
|
||||
|
||||
Changing cover image involves several steps. First remove original image by calling [RemoveFile](xref:Playnite.SDK.IGameDatabaseAPI.RemoveFile(System.String)) method. Then add new image file to a database using [AddFile](xref:Playnite.SDK.IGameDatabaseAPI.AddFile(System.String,System.Guid)). And lastly assign Id of new image to a game.
|
||||
|
||||
Following example changes cover image of first game in database:
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
var game = PlayniteApi.Database.Games[SomeId];
|
||||
PlayniteApi.Database.RemoveFile(game.CoverImage);
|
||||
game.CoverImage = PlayniteApi.Database.AddFile(@"c:\file.png", game.Id);
|
||||
PlayniteApi.Database.Games.Update(game);
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
$game = $PlayniteApi.Database.Games[SomeId]
|
||||
$PlayniteApi.Database.RemoveFile($game.CoverImage)
|
||||
$game.CoverImage = $PlayniteApi.Database.AddFile("c:\file.png", $game.Id)
|
||||
$PlayniteApi.Database.Games.Update($game)
|
||||
```
|
||||
***
|
||||
@ -1,93 +0,0 @@
|
||||
Library Plugins
|
||||
=====================
|
||||
|
||||
To implement library plugin:
|
||||
|
||||
* Read the introduction to [extensions](intro.md) and [plugins](plugins.md).
|
||||
* Create new public class inheriting from [LibraryPlugin](xref:Playnite.SDK.Plugins.LibraryPlugin) abstract class.
|
||||
* Add implementation for mandatory abstract members.
|
||||
|
||||
Mandatory members
|
||||
---------------------
|
||||
|
||||
| Member | Description |
|
||||
| -- | -- |
|
||||
| Id | Unique plugin id. |
|
||||
| Name | Library name. |
|
||||
| GetGames | Return games available in library. |
|
||||
|
||||
`GetGames` returns list of [Game](xref:Playnite.SDK.Models.Game) objects and these properties must be set correctly by the plugin in order for game to be imported properly:
|
||||
|
||||
| Member | Description |
|
||||
| -- | -- |
|
||||
| GameId | Unique identifier used to differentiate games of the same plugin. |
|
||||
| PluginId | Source Id of the plugin importing game. |
|
||||
| PlayAction | Game action used to start the game. Only if game is reported as installed via `State` property. |
|
||||
| InstallDirectory | Installation location. Only if game is reported as installed via `State` property. |
|
||||
|
||||
You can implement additional functionality by overriding virtual methods from [LibraryPlugin](xref:Playnite.SDK.Plugins.LibraryPlugin) base class.
|
||||
|
||||
Capabilities
|
||||
---------------------
|
||||
|
||||
If you want to provide extra features for specific library integration, like ability to close third party client after the game is close, then implement `Properties` property on your plugin class that represents [LibraryPluginProperties](xref:Playnite.SDK.Plugins.LibraryPluginProperties).
|
||||
|
||||
### Supported properties
|
||||
|
||||
| Capability | Description |
|
||||
| -- | -- |
|
||||
| CanShutdownClient | When supported, library's client object has to implement `Shutdown` method. |
|
||||
| HasCustomizedGameImport | Specifies that library is in full control over the game import mechanism. In this case the library should implement `ImportGames` method instead of `GetGames`. |
|
||||
|
||||
Example plugin
|
||||
---------------------
|
||||
|
||||
```csharp
|
||||
public class LibraryPlugin : LibraryPlugin
|
||||
{
|
||||
public override Guid Id { get; } = Guid.Parse("D625A3B7-1AA4-41CB-9CD7-74448D28E99B");
|
||||
|
||||
public override string Name { get; } = "Test Library";
|
||||
|
||||
public TestGameLibrary(IPlayniteAPI api) : base (api)
|
||||
{
|
||||
Properties = new LibraryPluginProperties
|
||||
{
|
||||
CanShutdownClient = true,
|
||||
HasSettings = true
|
||||
};
|
||||
}
|
||||
|
||||
public override IEnumerable<GameInfo> GetGames()
|
||||
{
|
||||
return new List<GameInfo>()
|
||||
{
|
||||
new GameInfo()
|
||||
{
|
||||
Name = "Notepad",
|
||||
GameId = "notepad",
|
||||
PlayAction = new GameAction()
|
||||
{
|
||||
Type = GameActionType.File,
|
||||
Path = "notepad.exe"
|
||||
},
|
||||
IsInstalled = true,
|
||||
Icon = @"c:\Windows\notepad.exe"
|
||||
},
|
||||
new GameInfo()
|
||||
{
|
||||
Name = "Calculator",
|
||||
GameId = "calc",
|
||||
PlayAction = new GameAction()
|
||||
{
|
||||
Type = GameActionType.File,
|
||||
Path = "calc.exe"
|
||||
},
|
||||
IsInstalled = true,
|
||||
Icon = @"https://playnite.link/applogo.png",
|
||||
BackgroundImage = @"https://playnite.link/applogo.png"
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -1,37 +0,0 @@
|
||||
Extension localizations
|
||||
=====================
|
||||
|
||||
Info
|
||||
---------------------
|
||||
|
||||
To add support for multiple languages:
|
||||
- Create `Localization` directory in root of your extension.
|
||||
- English is considered as base language, put all default strings into `en_US.xaml` file.
|
||||
- Other languages must be stored in `{locale}.xaml` files. For example `cs_CZ.xaml` for Czech language.
|
||||
|
||||
List of currently supported languages can be seen [here](https://github.com/JosefNemec/Playnite/tree/master/source/Playnite/Localization).
|
||||
|
||||
Localization files must contain proper `ResourceDictionary` objects, otherwise they won't be loaded. You can see examples of localization files [here](https://github.com/JosefNemec/Playnite/tree/master/source/Playnite/Localization).
|
||||
|
||||
> [!WARNING]
|
||||
> String keys are shared between all extensions so make sure you use unique keys for your extension if there's a possibility of a conflict.
|
||||
|
||||
Getting localized strings
|
||||
---------------------
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
var locString = ResourceProvider.GetString("stringkey");
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
$locString = [Playnite.SDK.ResourceProvider]::GetString("stringkey")
|
||||
```
|
||||
***
|
||||
|
||||
To reference localized string in XAML view, use `DynamicResource` markup.
|
||||
|
||||
```xml
|
||||
<TextBlock Text="{DynamicResource stringkey}" />
|
||||
```
|
||||
@ -1,36 +0,0 @@
|
||||
Writing to Log Files
|
||||
=====================
|
||||
|
||||
Introduction
|
||||
---------------------
|
||||
|
||||
Playnite provides built-in API for message logging. Messages from extensions are logged into `extensions.log` file that can be found in `%AppData%\Playnite` (for installed version) or in Playnite's installation directory (for portable versions).
|
||||
|
||||
> [!NOTE]
|
||||
> Messages with `Trace` severity are not written into log files unless enabled in `For developers` settings menu.
|
||||
|
||||
Scripts
|
||||
---------------------
|
||||
|
||||
To write message into Playnite's log files use `__logger` variable which profiles [ILogger](xref:Playnite.SDK.ILogger) interface.
|
||||
|
||||
Plugins
|
||||
---------------------
|
||||
|
||||
Use static `GetLogger` method from [LogManager](xref:Playnite.SDK.LogManager) class, to create logger instance.
|
||||
|
||||
Examples
|
||||
---------------------
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
var logger = LogManager.GetLogger();
|
||||
logger.Info("This is message with Info severity");
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
$__logger.Info("This is message with Info severity")
|
||||
```
|
||||
***
|
||||
|
||||
@ -1,118 +0,0 @@
|
||||
Custom application menus
|
||||
=====================
|
||||
|
||||
Basics
|
||||
---------------------
|
||||
|
||||
You can add new entries into main menu and game menu. Custom menu entries are currently only supported in Desktop mode.
|
||||
|
||||
Basics
|
||||
---------------------
|
||||
|
||||
To add new custom menu entries, implement appropriate menu script/plugin functions. Functions should return list of items that will be addded to a menu. Playnite passes [GetGameMenuItemsArgs](xref:Playnite.SDK.Plugins.GetGameMenuItemsArgs) and [GetMainMenuItemsArgs](xref:Playnite.SDK.Plugins.GetMainMenuItemsArgs) objects when the menu function is called.
|
||||
|
||||
You can use those argument objects to decide what elements to return. For example, in case of game menu, `GetGameMenuItemsArgs` contains `Games` field listing all currently selected games that are being used as a source for the game menu.
|
||||
|
||||
When the function associated with the menu item is invoked, it will be passed an arguments object. For game menu actions, C# extensions will be passed [GameMenuItemActionArgs](xref:Playnite.SDK.Plugins.GameMenuItemActionArgs) and script extensions will be passed [ScriptGameMenuItemActionArgs](xref:Playnite.SDK.Plugins.ScriptGameMenuItemActionArgs). `GameMenuItemActionArgs` has a `Games` property to access the selected list of games. For main menu actions, C# extensions will be passed [MainMenuItemActionArgs](xref:Playnite.SDK.Plugins.MainMenuItemActionArgs) and script extensions will be passed [ScriptMainMenuItemActionArgs](xref:Playnite.SDK.Plugins.ScriptMainMenuItemActionArgs).
|
||||
|
||||
> [!NOTE]
|
||||
> `Get*MenuItems` menu methods are executed each time a menu is opened. For that reason, make sure you are not executing long running code in those methods. It would otherwise result in a noticeable delay when opening the menu.
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
// To add new game menu items override GetGameMenuItems
|
||||
public override List<GameMenuItem> GetGameMenuItems(GetGameMenuItemsArgs args)
|
||||
{
|
||||
return new List<GameMenuItem>
|
||||
{
|
||||
new GameMenuItem
|
||||
{
|
||||
Description = "Name of game menu item",
|
||||
Action = (args) =>
|
||||
{
|
||||
// use args.Games to get list of games attached to the menu source
|
||||
Console.WriteLine("Invoked from game menu item!");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// To add new main menu items override GetMainMenuItems
|
||||
public override List<MainMenuItem> GetMainMenuItems(GetMainMenuItemsArgs args)
|
||||
{
|
||||
return new List<MainMenuItem>
|
||||
{
|
||||
new MainMenuItem
|
||||
{
|
||||
Description = "Name of main menu item",
|
||||
Action = (args) => Console.WriteLine("Invoked from main menu item!")
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
# To add new game menu items implement GetGameMenuItems
|
||||
function GetGameMenuItems()
|
||||
{
|
||||
param($getGameMenuItemsArgs)
|
||||
|
||||
$menuItem = New-Object Playnite.SDK.Plugins.ScriptGameMenuItem
|
||||
$menuItem.Description = "PowerShell game menu item"
|
||||
$menuItem.FunctionName = "InvokeGameMenuFunction"
|
||||
return $menuItem
|
||||
}
|
||||
|
||||
# To add new main menu items implement GetMainMenuItems
|
||||
function GetMainMenuItems()
|
||||
{
|
||||
param($getMainMenuItemsArgs)
|
||||
|
||||
$menuItem = New-Object Playnite.SDK.Plugins.ScriptMainMenuItem
|
||||
$menuItem.Description = "PowerShell main menu item"
|
||||
$menuItem.FunctionName = "InvokeMainMenuFunction"
|
||||
return $menuItem
|
||||
}
|
||||
|
||||
function InvokeGameMenuFunction()
|
||||
{
|
||||
param($scriptGameMenuItemActionArgs)
|
||||
# use $scriptGameMenuItemActionArgs.Games to get list of games attached to the menu source
|
||||
}
|
||||
|
||||
function InvokeMainMenuFunction()
|
||||
{
|
||||
param($scriptMainMenuItemActionArgs)
|
||||
}
|
||||
```
|
||||
***
|
||||
|
||||
Sub sections
|
||||
---------------------
|
||||
|
||||
You can add sub sections to menus by assigning `MenuSection` property, sections can be nested. Sub sections are shared between extensions allowing multiple extensions to add items to a single sub section.
|
||||
|
||||
To add a menu item under single sub section, assign a string value: `Section name`.
|
||||
|
||||
To add nested sections, separate definition with pipes: `Section name|Sub section name`.
|
||||
|
||||
To add items under "Extensions" main menu section, add `@` to the beginning of the section definition.
|
||||
|
||||
Icons
|
||||
---------------------
|
||||
|
||||
To add an icon to a menu item, assign a value to `Icon` property of menu item. Currently supported values are:
|
||||
|
||||
- Full path to an image file.
|
||||
- Theme relative file path to an image file.
|
||||
- Key of an application resource.
|
||||
|
||||
Separators
|
||||
---------------------
|
||||
|
||||
To add a separator, return new menu item with `Description` field se to `-`.
|
||||
|
||||
```csharp
|
||||
new GameMenuItem { Description = "-" }
|
||||
```
|
||||
@ -1,53 +0,0 @@
|
||||
Metadata Plugins
|
||||
=====================
|
||||
|
||||
To implement metadata plugin:
|
||||
|
||||
* Read the introduction to [extensions](intro.md) and [plugins](plugins.md).
|
||||
* Create new public class inheriting from [MetadataPlugin](xref:Playnite.SDK.Plugins.MetadataPlugin) abstract class.
|
||||
* Add implementation for mandatory abstract members.
|
||||
|
||||
Mandatory members
|
||||
---------------------
|
||||
|
||||
| Member | Description |
|
||||
| -- | -- |
|
||||
| Id | Unique plugin id. |
|
||||
| Name | Provider name. |
|
||||
| SupportedFields | Returns list of metadata fields this plugin can generally provide. |
|
||||
| GetMetadataProvider | Returns metadata provider class for specific metadata request. |
|
||||
|
||||
|
||||
OnDemandMetadataProvider
|
||||
---------------------
|
||||
|
||||
[OnDemandMetadataProvider](xref:Playnite.SDK.Plugins.OnDemandMetadataProvider) is an object to be returned from `GetMetadataProvider` method. Playnite uses it to request specific metadata fields based on user's metadata download settings. Override specific `Get*` methods based on what your plugin can provide. The class also contains another implementation of `AvailableFields` property, which should return list available fields for specific request.
|
||||
|
||||
`OnDemandMetadataProvider` is `IDisposable` and object is disposed automatically once metadata are processes completely for a single game.
|
||||
|
||||
MetadataRequestOptions
|
||||
---------------------
|
||||
[MetadataRequestOptions](xref:Playnite.SDK.Plugins.MetadataRequestOptions) is passed into every `GetMetadataProvider` request for each specific game. Most important fields are `IsBackgroundDownload` and `GameData`.
|
||||
|
||||
- `IsBackgroundDownload` indicates whether the download is being processed in background. By either automatically started download for newly imported games or manually initiated bulk download. When set to false it indicates that download is for manually initiated request from game edit dialog.
|
||||
|
||||
- `GameData` contains game that should be updated we new metadata.
|
||||
|
||||
MetadataProperty
|
||||
---------------------
|
||||
|
||||
Some fields like `Genres`, `Tags` and others that are globally stored as static values and shared between games are referenced by metadata sources via `MetadataProperty`. Based on what type is used to reference metadata, Playnite will use different method to assign final data.
|
||||
|
||||
Available property types:
|
||||
|
||||
| Type | Description |
|
||||
| --- | --- |
|
||||
| MetadataNameProperty | Playnite will assign field value based on a name (Playnite 8 behavior). If fields with the same name exists in game library, it's reused. |
|
||||
| MetadataIdProperty | Playnite will assign field value based on objects database ID. Use if you want to reference specific object already existing in the game library. |
|
||||
| MetadataSpecProperty | Playnite will assign filed value based on specification identifier. Currently only available for [Platforms](https://github.com/JosefNemec/Playnite/blob/devel/source/Playnite/Emulation/Platforms.yaml) and [Regions](https://github.com/JosefNemec/Playnite/blob/devel/source/Playnite/Emulation/Regions.yaml). Identifier matches based on an ID or a Name. |
|
||||
|
||||
|
||||
Example plugin
|
||||
---------------------
|
||||
|
||||
Playnite's IGDB integration is implemented as a metadata plugin. You can see the source [on GitHub](https://github.com/JosefNemec/Playnite/tree/devel/source/Plugins/IGDBMetadata).
|
||||
@ -1,172 +0,0 @@
|
||||
Plugin settings
|
||||
=====================
|
||||
|
||||
Basics
|
||||
---------------------
|
||||
|
||||
Plugins can provide configuration view that end users can use to change plugin's behavior. This includes UI component to display settings objects and input verification methods.
|
||||
|
||||
Plugins providing settings have to `HasSettings` plugin property set to `true`.
|
||||
|
||||
Implementation
|
||||
---------------------
|
||||
|
||||
Settings support requires that you override methods `GetSettings` and `GetSettingsView` methods. `GetSettings` returns `ISettings` object containing the settings data, while `GetSettingsView` returns WPF `UserControl` used to display that data.
|
||||
|
||||
### 1. Settings class
|
||||
|
||||
Following example show settings object implementing two custom plugin setting options and sets their default value.
|
||||
|
||||
```csharp
|
||||
public class TestPluginSettings : ISettings
|
||||
{
|
||||
public string Option1 { get; set; } = string.Empty;
|
||||
|
||||
public bool Option2 { get; set; } = false;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Implementing ISettings
|
||||
|
||||
Our example class is not complete since we don't have an implementation for all `ISettings` methods. Following example show all methods required for complete `ISettings` implementation.
|
||||
|
||||
```csharp
|
||||
public void BeginEdit()
|
||||
{
|
||||
// Code executed when settings view is opened and user starts editing values.
|
||||
}
|
||||
|
||||
public void CancelEdit()
|
||||
{
|
||||
// Code executed when user decides to cancel any changes made since BeginEdit was called.
|
||||
// This method should revert any changes made to Option1 and Option2.
|
||||
}
|
||||
|
||||
public void EndEdit()
|
||||
{
|
||||
// Code executed when user decides to confirm changes made since BeginEdit was called.
|
||||
// This method should save settings made to Option1 and Option2.
|
||||
}
|
||||
|
||||
public bool VerifySettings(out List<string> errors)
|
||||
{
|
||||
// Code execute when user decides to confirm changes made since BeginEdit was called.
|
||||
// Executed before EndEdit is called and EndEdit is not called if false is returned.
|
||||
// List of errors is presented to user if verification fails.
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Implementing settings view
|
||||
|
||||
Settings view is must be standard WPF UserControl. To add new control into your plugin project:
|
||||
|
||||
- Right click on your project, select **Add** -> **New Item...**.
|
||||
- Select **WPF** from the list of control templates and choose **User Control (WPF)** template.
|
||||
- Change name of the control to something like `NameOfMyPluginSettingsView.xaml` and save.
|
||||
- Open `NameOfMyPluginSettingsView.xaml` and implement the view.
|
||||
|
||||
Plugin's `ISettings` object is set by Playnite as data context while the view is being created (when user starts editing the settings), so you can directly bind it.
|
||||
|
||||
Following example show implementation of text field for our `Option1` value and check box for `Option2`.
|
||||
|
||||
```xml
|
||||
<UserControl x:Class="TestPlugin.TestPluginSettingsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Description for Option1:" />
|
||||
<TextBox Text="{Binding Option1}" />
|
||||
<TextBlock Text="Description for Option2:" />
|
||||
<CheckBox IsChecked="{Binding Option2}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
```
|
||||
|
||||
### 4. Hooking everything to a plugin class
|
||||
|
||||
As stated before, plugin class must override `GetSettings` and `GetSettingsView` methods.
|
||||
|
||||
```csharp
|
||||
public class TestPlugin : Plugin // or LibraryPlugin for library plugins, implementation is the same.
|
||||
{
|
||||
public override ISettings GetSettings(bool firstRunSettings)
|
||||
{
|
||||
return new TestPluginSettings();
|
||||
}
|
||||
|
||||
public override UserControl GetSettingsView(bool firstRunSettings)
|
||||
{
|
||||
return new TestPluginSettingsView();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Saving and loading settings
|
||||
---------------------
|
||||
|
||||
To store your settings permanently you have to implement some logic that will store data into some permanent storage and load them then time your plugin is loaded. You can do this manually or use built-in method that Playnite provides for this purpose.
|
||||
|
||||
Following example shows how to load and save values for your plugin.
|
||||
|
||||
```csharp
|
||||
public class TestPluginSettings : ObservableObject, ISettings
|
||||
{
|
||||
private TestPlugin plugin;
|
||||
|
||||
private string option1 = string.Empty;
|
||||
private bool option2 = false;
|
||||
private bool optionThatWontBeSaved = false;
|
||||
|
||||
public string Option1 { get => option1; set => SetValue(ref option1, value); }
|
||||
public bool Option2 { get => option2; set => SetValue(ref option2, value); }
|
||||
// Playnite serializes settings object to a JSON object and saves it as text file.
|
||||
// If you want to exclude some property from being saved then use `JsonDontSerialize` ignore attribute.
|
||||
[DontSerialize]
|
||||
public bool OptionThatWontBeSaved { get => optionThatWontBeSaved; set => SetValue(ref optionThatWontBeSaved, value); }
|
||||
|
||||
// Parameterless constructor must exist if you want to use LoadPluginSettings method.
|
||||
public TestPluginSettings()
|
||||
{
|
||||
}
|
||||
|
||||
public TestPluginSettings(TestPlugin plugin)
|
||||
{
|
||||
// Injecting your plugin instance is required for Save/Load method because Playnite saves data to a location based on what plugin requested the operation.
|
||||
this.plugin = plugin;
|
||||
|
||||
// Load saved settings.
|
||||
var savedSettings = plugin.LoadPluginSettings<TestPluginSettings>();
|
||||
|
||||
// LoadPluginSettings returns null if not saved data is available.
|
||||
if (savedSettings != null)
|
||||
{
|
||||
Option1 = savedSettings.Option1;
|
||||
Option2 = savedSettings.Option2;
|
||||
}
|
||||
}
|
||||
|
||||
// To save settings just call SavePluginSettings when user confirms changes.
|
||||
public void EndEdit()
|
||||
{
|
||||
plugin.SavePluginSettings(this);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Settings workflow
|
||||
---------------------
|
||||
|
||||
When user opens settings window in Playnite, following happens with your plugin:
|
||||
|
||||
- Playnite gets `GetSettings` and `GetSettingsView` values from your plugin.
|
||||
- `Settings` object is set as `DataContext` of `SettingsView` view.
|
||||
- `BeginEdit` method is called.
|
||||
|
||||
- When user decides to cancel editing of settings:
|
||||
- `CancelEdit` is called.
|
||||
|
||||
- When use decides to confirm changes:
|
||||
- `VerifySettings` is called:
|
||||
- If `false` is returned Playnite shows verification errors to a user.
|
||||
- If `true` is returned `EndEdit` is called.
|
||||
@ -1,94 +0,0 @@
|
||||
Plugins Introduction
|
||||
=====================
|
||||
|
||||
Basics
|
||||
---------------------
|
||||
|
||||
Plugins can be written in any .NET Framework compatible languages, this includes C#, VB.NET, F# and others, targeting .NET Framework 4.6.
|
||||
|
||||
Plugin types
|
||||
---------------------
|
||||
|
||||
There are currently two types of plugins:
|
||||
|
||||
- `Generic plugins` Generic plugins offer same extensibility as scripts. You can add new entries to main menu or react to various [game events](events.md).
|
||||
|
||||
- `Library plugins`: Add ability to import games automatically as well as methods for metadata download for those games.
|
||||
|
||||
- `Metadata plugins`: Add ability to import game metadata.
|
||||
|
||||
Creating plugins
|
||||
---------------------
|
||||
|
||||
### Using Toolbox
|
||||
|
||||
#### 1. Generate from template
|
||||
|
||||
Run [Toolbox](../toolbox.md) with arguments specific to a type of plugin you want to create.
|
||||
|
||||
For example, to create new library plugin:
|
||||
|
||||
```cmd
|
||||
Toolbox.exe new LibraryPlugin "SomeLibrary importer" "d:\somefolder"
|
||||
```
|
||||
|
||||
This will generate new C# project, with all of required classes already premade.
|
||||
|
||||
#### 2. Implement functionality
|
||||
|
||||
Don't forget to implement functionality for template methods and properties that by default return `NotImplementedException` exception.
|
||||
|
||||
> [!NOTE]
|
||||
If you are having issue compiling plugin created from the template, then make sure that nuget dependencies are downloaded and installed properly. You can do that by using "Manage NuGet Packages" menu after right-clicking on plugin solution/project in solution explorer.
|
||||
|
||||
### Manually
|
||||
|
||||
#### 1. Create plugin project
|
||||
|
||||
Start by creating new `Class Library` project targeting `.NET Framework 4.6.2`. Add [Playnite SDK](https://www.nuget.org/packages/PlayniteSDK/) nuget package reference and set reference to not require specific version (right-click on `Playnite.SDK` reference, choose `Properties` and set `Specific Version` to false).
|
||||
|
||||
> [!NOTE]
|
||||
> PlayniteSDK is designed in a way that all versions from one major version branch (for example 1.0, 1.1, 1.2 etc.) are backwards compatible. Therefore plugin written for SDK version 1.0 will also work with Playnite containing all 1.x versions of SDK. When loading plugins Playnite checks all SDK references and won't load plugins referencing incompatible SDK versions.
|
||||
|
||||
#### 2. Write a plugin
|
||||
|
||||
- `Generic plugins` - see generic plugins [documentation page](genericPlugins.md).
|
||||
- `Library plugins` - see library plugins [documentation page](libraryPlugins.md).
|
||||
- `Metadata plugins` - see metadata plugins [documentation page](metadataPlugins.md).
|
||||
|
||||
#### 3. Create manifest file
|
||||
|
||||
Described in [introduction section](intro.md) to extensions.
|
||||
|
||||
Plugin dependencies
|
||||
---------------------
|
||||
|
||||
> [!WARNING]
|
||||
> If you are using external dependencies (from NuGet for example), make sure that you use the same version that Playnite already references. Current plugin system doesn't allow loading of multiple versions of the same assembly and you may encounter issues if you use different version compared to what Playnite uses.
|
||||
|
||||
You can check list of all Playnite's dependencies here:
|
||||
|
||||
- [Playnite](https://github.com/JosefNemec/Playnite/blob/master/source/Playnite/packages.config)
|
||||
- [Playnite.Common](https://github.com/JosefNemec/Playnite/blob/master/source/Playnite.Common/packages.config)
|
||||
- [Playnite.DesktopApp](https://github.com/JosefNemec/Playnite/blob/master/source/Playnite.DesktopApp/packages.config)
|
||||
- [Playnite.FullscreenApp](https://github.com/JosefNemec/Playnite/blob/master/source/Playnite.FullscreenApp/packages.config)
|
||||
|
||||
Referencing Playnite assemblies
|
||||
---------------------
|
||||
|
||||
> [!WARNING]
|
||||
> **DO NOT** reference non-SDK Playnite assemblies in your project (`Playnite`, `Playnite.Common` etc.). Playnite will refuse to load plugins that reference those assemblies.
|
||||
|
||||
If you want to use functionality/code from non-SDK assemblies, you have several options:
|
||||
* Open GitHub issues for the functionality to be exposed in the SDK.
|
||||
* Link the source code to your project (choose "Add as link" when adding a source file into plugin project) and compile it with your plugin assembly.
|
||||
|
||||
Plugin settings
|
||||
---------------------
|
||||
|
||||
If you want to give user ability to change plugin behavior, you can do that by implementing appropriate settings overrides from `Plugin` abstract class. Including ability to add fully customizable UI for your configuration that will be accessible in Playnite's settings windows. To add plugin settings support to your plugin follow [Plugin settings guide](pluginSettings.md).
|
||||
|
||||
Examples
|
||||
---------------------
|
||||
|
||||
Support for all 3rd part clients in Playnite is implemented fully using plugins so you can use then as a reference when implementing new ones. Source can be found [on GitHub](https://github.com/JosefNemec/Playnite/tree/master/source/Plugins).
|
||||
@ -1,96 +0,0 @@
|
||||
Playnite Scripting Introduction
|
||||
=====================
|
||||
|
||||
Basics
|
||||
---------------------
|
||||
|
||||
Playnite can be extended with additional functionality using scripts. [PowerShell](https://docs.microsoft.com/en-us/powershell/) is currently the only supported scripting language.
|
||||
|
||||
> [!NOTE]
|
||||
> PowerShell support requires PowerShell 5.1 to be installed on your machine. If you are Windows 7 user, you need to [install it manually](https://www.microsoft.com/en-us/download/details.aspx?id=54616) (Windows 8 and 10 includes it by default). This also means that PowerShell functionality is restricted to 5.x version. Playnite currently doesn't support newer PowerShell Core runtime (PowerShell versions 6 and newer).
|
||||
|
||||
PowerShell extensions are imported as a [PowerShell module](https://docs.microsoft.com/en-us/powershell/scripting/developer/module/how-to-write-a-powershell-script-module?view=powershell-5.1). The extension of the file must be `.psm1` (or `.psd1` if you use a [PowerShell module manifest](https://docs.microsoft.com/en-us/powershell/scripting/developer/module/how-to-write-a-powershell-module-manifest?view=powershell-5.1)).
|
||||
|
||||
Any exported functions from your extension must be exported from the module. In a `.psm1` file all functions in the module scope are exported by default, but functions in the global scope (defined like `function global:OnGameStarted()`) will _not_ be correctly exported.
|
||||
|
||||
Creating script extensions
|
||||
---------------------
|
||||
|
||||
Run [Toolbox](../toolbox.md) with arguments specific to a type of script you want to create.
|
||||
|
||||
To create new PowerShell script extension:
|
||||
|
||||
```cmd
|
||||
Toolbox.exe new PowerShellScript "Some script" "d:\somefolder"
|
||||
```
|
||||
|
||||
Accessing Playnite API
|
||||
---------------------
|
||||
|
||||
Playnite API is available to scripts via `PlayniteAPI` variable. Variable provides [IPlayniteAPI](xref:Playnite.SDK.IPlayniteAPI) methods and interfaces. For example to get list of all games in library use [Database](xref:Playnite.SDK.IPlayniteAPI.Database) property from `IPlayniteAPI` and [Games](xref:Playnite.SDK.IGameDatabase.Games) collection.
|
||||
|
||||
```powershell
|
||||
$PlayniteAPI.Database.Games
|
||||
```
|
||||
|
||||
To display number of games use `Dialogs` property from `PlayniteApi` variable. `Dialogs` provides [IDialogsFactory](xref:Playnite.SDK.IDialogsFactory) interface containing method for interaction with user. `ShowMessage` method will show simple text message to user.
|
||||
|
||||
```powershell
|
||||
$gameCount = $PlayniteApi.Database.Games.Count
|
||||
$PlayniteApi.Dialogs.ShowMessage($gameCount)
|
||||
```
|
||||
|
||||
Examples
|
||||
---------------------
|
||||
|
||||
Displays number of games in the game library when executing `Show Game Count` menu from `Extensions` menu.
|
||||
|
||||
```powershell
|
||||
function DisplayGameCount()
|
||||
{
|
||||
param(
|
||||
$scriptMainMenuItemActionArgs
|
||||
)
|
||||
|
||||
$gameCount = $PlayniteApi.Database.Games.Count
|
||||
$PlayniteApi.Dialogs.ShowMessage($gameCount)
|
||||
}
|
||||
|
||||
function GetMainMenuItems()
|
||||
{
|
||||
param(
|
||||
$getMainMenuItemsArgs
|
||||
)
|
||||
|
||||
$menuItem = New-Object Playnite.SDK.Plugins.ScriptMainMenuItem
|
||||
$menuItem.Description = "Show Game Count"
|
||||
$menuItem.FunctionName = "DisplayGameCount"
|
||||
$menuItem.MenuSection = "@"
|
||||
return $menuItem
|
||||
}
|
||||
```
|
||||
|
||||
Troubleshooting
|
||||
---------------------
|
||||
|
||||
### Debugging
|
||||
|
||||
See [scripting debugging](scriptingDebugging.md) page for more details about how to debug PowerShell code running in Playnite.
|
||||
|
||||
### Exceptions related to directory not being found
|
||||
|
||||
Paths (and strings in general) in various places in PowerShell are handled not as literal strings, but as strings with wildcard patterns. This has unfortunate issue if specific command doesn't allow you to pass literal string via a specific argument (for example `-LiteralPath`) or has an option to disable wildcard parsing.
|
||||
|
||||
This can cause issues if game's installation path contains wildcard pattern characters. For example game installed in `d:\[test] game name\` will cause issues to `Start-Process` cmdlet, because of `[` and `]` pattern characters. This is because Playnite sets script runtime's working directory to game's installation path and Start-Process tries to parse it before launching a program.
|
||||
|
||||
Solution is to either use literal path arguments or use different cmdlet or .NET classes directly. For example to start a process:
|
||||
|
||||
```powershell
|
||||
# Instead of:
|
||||
Start-Process "game.exe"
|
||||
|
||||
# call .NET class directly:
|
||||
[System.Diagnostics.Process]::Start("game.exe")
|
||||
```
|
||||
|
||||
Note: This issue has been fixed in newer versions of PowerShell, but since Playnite has to use older version (5.1) until we switch to newer .NET runtime, you may encounter this issue.
|
||||
@ -1,27 +0,0 @@
|
||||
Debugging Scripts
|
||||
=====================
|
||||
|
||||
Debugging PowerShell Scripts with PowerShell ISE
|
||||
---------------------
|
||||
|
||||
1. Open the 64-bit bit version of PowerShell ISE.
|
||||
2. Enter the PowerShell host process of Playnite:
|
||||
|
||||
```powershell
|
||||
Enter-PSHostProcess -Name Playnite.DesktopApp
|
||||
```
|
||||
3. Identify the correct runspace name of your script. It will be the name of the module file. Use the commands `Get-Runspace` or `(Get-Runspace).Name` to list runspaces.
|
||||
4. Debug the script by attaching to the runspace:
|
||||
|
||||
```powershell
|
||||
Debug-Runspace -Name "LibraryExporter.psm1"
|
||||
```
|
||||
5. The debugger will automatically break when code is executed. A tab named "[Remote File] LibraryExporter.psm1 [Read Only]" will appear in PowerShell ISE. To trigger the debugger to break, interact with the extension somehow. For example, click the Playnite menu button to break in `GetMainMenuItems`.
|
||||
6. Set breakpoints using Debug > Toggle Breakpoint.
|
||||
7. Continue execution by selecting Debug > Run/Continue.
|
||||
|
||||
When the breakpoint is reached, hover over any variable names to see their current value.
|
||||
|
||||
Typing into the PowerShell ISE console will evaluate statements in the current context. For example, you can use the `$PlayniteAPI` variable to interactively develop and test code. You may also interactively inspect local variables and their properties.
|
||||
|
||||
The Playnite interface will appear frozen while the debugger is paused on a breakpoint.
|
||||
@ -1,135 +0,0 @@
|
||||
Interacting with Playnite's UI
|
||||
=====================
|
||||
|
||||
Getting list of selected games
|
||||
---------------------
|
||||
|
||||
To get list of currently selected games use `MainView` from `PlayniteApi` variable. `MainView` provides [IMainViewAPI](xref:Playnite.SDK.IMainViewAPI) interface with [SelectedGames](xref:Playnite.SDK.IMainViewAPI.SelectedGames) property returning list of all selected games.
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
var gameCount = PlayniteApi.MainView.SelectedGames.Count;
|
||||
PlayniteApi.Dialogs.ShowMessage($"Selected {gameCount} games");
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
$PlayniteApi.MainView.SelectedGames | Select -ExpandProperty Name | Out-File "SelectedGames.txt"
|
||||
```
|
||||
***
|
||||
|
||||
Custom UI elements
|
||||
---------------------
|
||||
|
||||
See [custom UI integration](customUiIntegration.md) page for more details.
|
||||
|
||||
Menus
|
||||
---------------------
|
||||
|
||||
See [menus](menus.md) page for more details.
|
||||
|
||||
Dialogs
|
||||
---------------------
|
||||
|
||||
[IDialogsFactory](xref:Playnite.SDK.IDialogsFactory) API can be used to show various dialogs.
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
PlayniteApi.Dialogs.ShowMessage("Hello world!");
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
$PlayniteApi.Dialogs.ShowMessage("Hello world!")
|
||||
```
|
||||
***
|
||||
|
||||
Sidebar
|
||||
---------------------
|
||||
|
||||
To provide new items to the Sidebar, override `GetSidebarItems` method and return list of [SidebarItem](xref:Playnite.SDK.Plugins.SidebarItem) items.
|
||||
|
||||
### Item types
|
||||
|
||||
There are two types of Sidebar items set via `Type` property:
|
||||
- `Button`: Simple activation button.
|
||||
- `View`: View button that shows custom view when clicked.
|
||||
|
||||
To implement `Button` type: set `Type` property of a sidebar item to `Button` and assign action to `Activated` action.
|
||||
|
||||
To implement `View` type: set `Type` property of a sidebar item to `View` and assign `Opened` and `Closed` actions. `Opened` is called when user clicks the item and expects UI control to be returned (which is then loaded as a new Playnite view). `Closed` is called when user switches to a different view.
|
||||
|
||||
### Progress indicator
|
||||
|
||||
Sidebar items can also show progress indicator, use `ProgressValue` and `ProgressMaximum` properties to set a specific progress state. Setting `ProgressValue` to `0` hides the progress bar.
|
||||
|
||||
### Example
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
public override List<SidebarItem> GetSidebarItems()
|
||||
{
|
||||
return new List<SidebarItem>
|
||||
{
|
||||
new SidebarItem
|
||||
{
|
||||
Title = "Calculator",
|
||||
// Loads icon from plugin's installation path
|
||||
Icon = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "icon.png"),
|
||||
ProgressValue = 40,
|
||||
Activated = () => Process.Start("calc")
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
'Not supported in PowerShell extensions.'
|
||||
```
|
||||
***
|
||||
|
||||
Top panel
|
||||
---------------------
|
||||
|
||||
To provide new items to the Top panel, override `GetTopPanelItems` method and return list of [TopPanelItem](xref:Playnite.SDK.Plugins.TopPanelItem) items.
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
public override List<TopPanelItem> GetTopPanelItems()
|
||||
{
|
||||
return new List<TopPanelItem>
|
||||
{
|
||||
new TopPanelItem
|
||||
{
|
||||
Title = "Calculator",
|
||||
Icon = new TextBlock
|
||||
{
|
||||
Text = char.ConvertFromUtf32(0xeaf1),
|
||||
FontSize = 20,
|
||||
FontFamily = ResourceProvider.GetResource("FontIcoFont") as FontFamily
|
||||
},
|
||||
Activated = () => Process.Start("calc")
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
'Not supported in PowerShell extensions.'
|
||||
```
|
||||
***
|
||||
|
||||
Supported icons formats
|
||||
---------------------
|
||||
|
||||
Various objects support icon definitions that doesn't enforce specific format, like Sidebar or Top panel items. Icon is an `object` type and Playnite will interpret as this:
|
||||
|
||||
- If `string` is provided, Playnite interprets it in the following order:
|
||||
- If application resource with the name is found it's used.
|
||||
- If a file path is found, Playnite will try to load it as an image.
|
||||
- If partial file path is found:
|
||||
- Theme file is loaded as an image if found.
|
||||
- Database file is loaded an an image if found.
|
||||
- If any other type is found, Playnite assigns that object as icon's content.
|
||||
@ -1,22 +0,0 @@
|
||||
Playnite URI support
|
||||
=====================
|
||||
|
||||
Introduction
|
||||
---------------------
|
||||
|
||||
Plugins (scripts are not supported) can register custom methods to be executed when specific `playnite://` URI is opened. This can be done using `RegisterSource` method from [UriHandler](xref:Playnite.SDK.IPlayniteAPI.UriHandler) API.
|
||||
|
||||
Example
|
||||
---------------------
|
||||
|
||||
Following example executes method when `playnite://mysource/` URI is opened.
|
||||
|
||||
```csharp
|
||||
PlayniteApi.UriHandler.RegisterSource("mysource", (args) =>
|
||||
{
|
||||
// Code to be executed
|
||||
// Use args.Arguments to access URL arguments
|
||||
});
|
||||
```
|
||||
|
||||
In this example opening ``playnite://mysource/arg1/arg2` will call registered method and pass array of two arguments ("arg1" and "arg2") to it.
|
||||
@ -1,97 +0,0 @@
|
||||
Creating custom windows
|
||||
=====================
|
||||
|
||||
Intro
|
||||
---------------------
|
||||
|
||||
Manually created windows will not inherit Playnite's theme, you need to use [CreateWindow](xref:Playnite.SDK.IDialogsFactory.CreateWindow(Playnite.SDK.WindowCreationOptions)) to create a new window instance. `CreateWindow` returns new instance of WPF Window class.
|
||||
|
||||
Examples
|
||||
---------------------
|
||||
|
||||
# [C#](#tab/csharp)
|
||||
```csharp
|
||||
var window = PlayniteApi.Dialogs.CreateWindow(new WindowCreationOptions
|
||||
{
|
||||
ShowMinimizeButton = false
|
||||
});
|
||||
|
||||
window.Height = 1024;
|
||||
window.Width = 768;
|
||||
window.Title = "Some title";
|
||||
|
||||
// Set content of a window. Can be loaded from xaml, loaded from UserControl or created from code behind
|
||||
window.Content =
|
||||
|
||||
// Set data context if you want to use MVVM pattern
|
||||
window.DataContext =
|
||||
|
||||
// Set owner if you need to create modal dialog window
|
||||
window.Owner = PlayniteApi.Dialogs.GetCurrentAppWindow();
|
||||
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||
|
||||
// Use Show or ShowDialog to show the window
|
||||
window.ShowDialog();
|
||||
```
|
||||
|
||||
# [PowerShell](#tab/tabpowershell)
|
||||
```powershell
|
||||
$windowCreationOptions = New-Object Playnite.SDK.WindowCreationOptions
|
||||
$windowCreationOptions.ShowMinimizeButton = $false
|
||||
|
||||
$window = $PlayniteApi.Dialogs.CreateWindow($windowCreationOptions);
|
||||
$window.Height = 768;
|
||||
$window.Width = 768;
|
||||
$window.Title = "Some title";
|
||||
|
||||
# Set content of a window. Can be loaded from xaml, loaded from UserControl or created from code behind
|
||||
[xml]$xaml = @"
|
||||
<UserControl
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<UserControl.Resources>
|
||||
<Style TargetType="TextBlock" BasedOn="{StaticResource BaseTextBlockStyle}" />
|
||||
</UserControl.Resources>
|
||||
|
||||
<StackPanel Margin="15,0,0,0">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="An example button:" Margin="0,0,15,0" VerticalAlignment="Center"/>
|
||||
<Button x:Name="MyButton" Content="Click me!"/>
|
||||
</StackPanel>
|
||||
<TextBlock Text="Currently selected games:" Margin="0,15,0,0"/>
|
||||
<ItemsControl ItemsSource="{Binding}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Path=Name}" Margin="15,0,0,0"
|
||||
Style="{StaticResource BaseTextBlockStyle}"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,15,0,0">
|
||||
<TextBlock Text="Total selected games: "/>
|
||||
<TextBlock Text="{Binding .Count}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
"@
|
||||
$reader = [System.Xml.XmlNodeReader]::new($xaml)
|
||||
$window.Content = [Windows.Markup.XamlReader]::Load($reader)
|
||||
|
||||
# Set data context if you want to use MVVM pattern
|
||||
$window.DataContext = $PlayniteApi.MainView.SelectedGames
|
||||
|
||||
# Attach a click event handler
|
||||
$button = $window.Content.FindName("MyButton")
|
||||
$button.Add_Click({
|
||||
$button.Content = "Clicked"
|
||||
})
|
||||
|
||||
# Set owner if you need to create modal dialog window
|
||||
$window.Owner = $PlayniteApi.Dialogs.GetCurrentAppWindow();
|
||||
$window.WindowStartupLocation = "CenterOwner";
|
||||
|
||||
# Use Show or ShowDialog to show the window
|
||||
$window.ShowDialog();
|
||||
```
|
||||
***
|
||||
@ -1,173 +0,0 @@
|
||||
Playnite 9 add-on migration guide
|
||||
=====================
|
||||
|
||||
Extension load changes
|
||||
---------------------
|
||||
|
||||
### Scripts
|
||||
|
||||
**IronPython support has been removed completely, therefore you have to rewrite those to PowerShell.**
|
||||
|
||||
PowerShell extensions are now imported as [PowerShell modules](https://docs.microsoft.com/en-us/powershell/scripting/developer/module/how-to-write-a-powershell-script-module?view=powershell-5.1). The extension of the file must be `.psm1` (or `.psd1` if you use a [PowerShell module manifest](https://docs.microsoft.com/en-us/powershell/scripting/developer/module/how-to-write-a-powershell-module-manifest?view=powershell-5.1)).
|
||||
|
||||
Any exported functions from your extension must be exported from the module. In a `.psm1` file all functions in the module scope are exported by default, but functions in the global scope (defined like `function global:OnGameStarted()`) will _not_ be correctly exported. Exported functions must accept the *exact* number of arguments that Playnite passes to them.
|
||||
|
||||
### Plugins
|
||||
|
||||
Generic plugins now have to inherit from [GenericPlugin](xref:Playnite.SDK.Plugins.GenericPlugin) class, not `Plugin` class, otherwise they won't be loaded at all.
|
||||
|
||||
Model changes
|
||||
---------------------
|
||||
|
||||
Multiple changes have been made to various data models, properties removed, renamed, added. This primarily affects `Game` and `Emulator` objects.
|
||||
|
||||
> [!NOTE]
|
||||
> Since PowerShell is not statically typed language there's no easy way how to find all model changes you need to fix. Please take care and make sure that you fix and test your code properly, especially if you are writing data into game library, since you could write bad data it if you don't adjust your scripts properly.
|
||||
|
||||
File changes:
|
||||
|
||||
[M source/PlayniteSDK/BuiltInExtensions.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_BuiltInExtensions.cs.html)
|
||||
[M source/PlayniteSDK/Collections/ObservableObject.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Collections_ObservableObject.cs.html)
|
||||
[M source/PlayniteSDK/Data/DataSerialization.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Data_DataSerialization.cs.html)
|
||||
[M source/PlayniteSDK/Database/IGameDatabase.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Database_IGameDatabase.cs.html)
|
||||
[M source/PlayniteSDK/Database/IItemCollection.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Database_IItemCollection.cs.html)
|
||||
[M source/PlayniteSDK/Events/ApplicationEvents.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Events_ApplicationEvents.cs.html)
|
||||
[M source/PlayniteSDK/Exceptions/ScriptRuntimeException.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Exceptions_ScriptRuntimeException.cs.html)
|
||||
[M source/PlayniteSDK/ExpandableVariables.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_ExpandableVariables.cs.html)
|
||||
[M source/PlayniteSDK/Extensions/ListExtensions.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Extensions_ListExtensions.cs.html)
|
||||
[M source/PlayniteSDK/IDialogsFactory.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_IDialogsFactory.cs.html)
|
||||
[M source/PlayniteSDK/ILogger.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_ILogger.cs.html)
|
||||
[M source/PlayniteSDK/IMainViewAPI.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_IMainViewAPI.cs.html)
|
||||
[M source/PlayniteSDK/IPlayniteAPI.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_IPlayniteAPI.cs.html)
|
||||
[M source/PlayniteSDK/IPlayniteSettingsAPI.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_IPlayniteSettingsAPI.cs.html)
|
||||
[M source/PlayniteSDK/IWebView.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_IWebView.cs.html)
|
||||
[M source/PlayniteSDK/LogManager.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_LogManager.cs.html)
|
||||
[M source/PlayniteSDK/MetadataProvider.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_MetadataProvider.cs.html)
|
||||
[M source/PlayniteSDK/Models/AppSoftware.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Models_AppSoftware.cs.html)
|
||||
[M source/PlayniteSDK/Models/CompletionStatus.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Models_CompletionStatus.cs.html)
|
||||
[M source/PlayniteSDK/Models/DatabaseObject.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Models_DatabaseObject.cs.html)
|
||||
[M source/PlayniteSDK/Models/Emulator.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Models_Emulator.cs.html)
|
||||
[M source/PlayniteSDK/Models/Game.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Models_Game.cs.html)
|
||||
[M source/PlayniteSDK/Models/GameAction.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Models_GameAction.cs.html)
|
||||
[M source/PlayniteSDK/Models/PastTimeSegment.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Models_PastTimeSegment.cs.html)
|
||||
[M source/PlayniteSDK/Models/Platform.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Models_Platform.cs.html)
|
||||
[M source/PlayniteSDK/Models/Region.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Models_Region.cs.html)
|
||||
[M source/PlayniteSDK/Plugins/LibraryPlugin.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Plugins_LibraryPlugin.cs.html)
|
||||
[M source/PlayniteSDK/Plugins/MetadataPlugin.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Plugins_MetadataPlugin.cs.html)
|
||||
[M source/PlayniteSDK/Plugins/Plugin.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Plugins_Plugin.cs.html)
|
||||
[M source/PlayniteSDK/Properties/AssemblyInfo.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_Properties_AssemblyInfo.cs.html)
|
||||
[M source/PlayniteSDK/RelayCommand.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_RelayCommand.cs.html)
|
||||
[M source/PlayniteSDK/ResourceProvider.cs](https://playnite.link/sdkchangelog/5.5.0-6.0.0/PlayniteSDK_ResourceProvider.cs.html)
|
||||
|
||||
Method changes
|
||||
---------------------
|
||||
|
||||
All event and other methods that previously accepted multiple arguments have been consolidated into single argument object. This is true for both plugin and script methods.
|
||||
|
||||
Game action controllers
|
||||
---------------------
|
||||
|
||||
Controllers (for installing/uninstalling and starting games) have been reworked. See [related documentation page](../tutorials/extensions/gameActions.md) for more information about how to implement them in Playnite 9.
|
||||
|
||||
Metadata plugin changes
|
||||
---------------------
|
||||
|
||||
Metadata sources no longer return data as strings but instead use `MetadataProperty` objects. See [metadata plugin page](extensions/metadataPlugins.md#metadataproperty) for more information.
|
||||
|
||||
Other
|
||||
---------------------
|
||||
|
||||
Extensions no longer log into main log file (playnite.log), but use separate file called `extensions.log`.
|
||||
|
||||
Themes
|
||||
---------------------
|
||||
|
||||
Use Toolbox utility to update theme files to new version, this is absolutely necessary otherwise Blend will no longer load your theme properly. Note that some styles/views are no longer available, others have been moved or renamed. There are also new styles added to support styling of controls that were previously not exposed to themes (like filter panel dropdowns and search boxes).
|
||||
|
||||
Playnite 9 also changes how theme files are loaded, which should solve inheritance issue with static references. For example if you had custom CheckBox style then changes from global CheckBox style would not be applied to inherited style and you had to define the whole inherited style. This is no longer needed and theme global styles should be inherited properly.
|
||||
|
||||
File changes:
|
||||
|
||||
To see what letters before file change mean check [this page](https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---diff-filterACDMRTUXB82308203).
|
||||
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/Constants.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_Constants.xaml.html)
|
||||
A source/Playnite.DesktopApp/Themes/Desktop/Default/CustomControls/ComboBoxList.xaml
|
||||
A source/Playnite.DesktopApp/Themes/Desktop/Default/CustomControls/ExtendedDataGrid.xaml
|
||||
A source/Playnite.DesktopApp/Themes/Desktop/Default/CustomControls/FilterSelectionBox.xaml
|
||||
D source/Playnite.DesktopApp/Themes/Desktop/Default/CustomControls/MainMenu.xaml
|
||||
D source/Playnite.DesktopApp/Themes/Desktop/Default/CustomControls/NullableIntBox.xaml
|
||||
D source/Playnite.DesktopApp/Themes/Desktop/Default/CustomControls/NumericBox.xaml
|
||||
A source/Playnite.DesktopApp/Themes/Desktop/Default/CustomControls/NumericBoxes.xaml
|
||||
A source/Playnite.DesktopApp/Themes/Desktop/Default/CustomControls/PathSelectionBox.xaml
|
||||
A source/Playnite.DesktopApp/Themes/Desktop/Default/CustomControls/SearchBox.xaml
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/CustomControls/SidebarItem.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_CustomControls_SidebarItem.xaml.html)
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/CustomControls/SliderEx.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_CustomControls_SliderEx.xaml.html)
|
||||
A source/Playnite.DesktopApp/Themes/Desktop/Default/CustomControls/TopPanelItem.xaml
|
||||
D source/Playnite.DesktopApp/Themes/Desktop/Default/CustomControls/ViewSettingsMenu.xaml
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/DefaultControls/CheckBox.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_DefaultControls_CheckBox.xaml.html)
|
||||
A source/Playnite.DesktopApp/Themes/Desktop/Default/DefaultControls/DataGrid.xaml
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/DefaultControls/Expander.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_DefaultControls_Expander.xaml.html)
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/DefaultControls/ScrollViewer.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_DefaultControls_ScrollViewer.xaml.html)
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/DefaultControls/Slider.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_DefaultControls_Slider.xaml.html)
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/DefaultControls/TabControl.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_DefaultControls_TabControl.xaml.html)
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/DefaultControls/Thumb.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_DefaultControls_Thumb.xaml.html)
|
||||
A source/Playnite.DesktopApp/Themes/Desktop/Default/DerivedStyles/GridViewGroupStyle.xaml
|
||||
A source/Playnite.DesktopApp/Themes/Desktop/Default/DerivedStyles/ListViewGroupStyle.xaml
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/DerivedStyles/PlayButton.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_DerivedStyles_PlayButton.xaml.html)
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/DerivedStyles/PropertyItemButton.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_DerivedStyles_PropertyItemButton.xaml.html)
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/Media.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_Media.xaml.html)
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/Views/DetailsViewGameOverview.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_Views_DetailsViewGameOverview.xaml.html)
|
||||
D source/Playnite.DesktopApp/Themes/Desktop/Default/Views/FilterPanel.xaml
|
||||
A source/Playnite.DesktopApp/Themes/Desktop/Default/Views/FilterPanelView.xaml
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/Views/GridViewGameOverview.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_Views_GridViewGameOverview.xaml.html)
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/Views/Library.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_Views_Library.xaml.html)
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/Views/LibraryDetailsView.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_Views_LibraryDetailsView.xaml.html)
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/Views/LibraryGridView.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_Views_LibraryGridView.xaml.html)
|
||||
D source/Playnite.DesktopApp/Themes/Desktop/Default/Views/MainPanel.xaml
|
||||
[M source/Playnite.DesktopApp/Themes/Desktop/Default/Views/Sidebar.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.DesktopApp_Themes_Desktop_Default_Views_Sidebar.xaml.html)
|
||||
A source/Playnite.DesktopApp/Themes/Desktop/Default/Views/TopPanel.xaml
|
||||
D source/Playnite.DesktopApp/Themes/Desktop/DefaultRed/Constants.xaml
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Constants.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_Constants.xaml.html)
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/CustomControls/FilterDbItemtSelection.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_CustomControls_FilterDbItemtSelection.xaml.html)
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/CustomControls/FilterEnumListSelection.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_CustomControls_FilterEnumListSelection.xaml.html)
|
||||
A source/Playnite.FullscreenApp/Themes/Fullscreen/Default/CustomControls/FilterPresetSelector.xaml
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/CustomControls/FilterStringListSelection.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_CustomControls_FilterStringListSelection.xaml.html)
|
||||
D source/Playnite.FullscreenApp/Themes/Fullscreen/Default/CustomControls/WindowBase.xaml
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DefaultControls/Button.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_DefaultControls_Button.xaml.html)
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DefaultControls/CheckBox.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_DefaultControls_CheckBox.xaml.html)
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DefaultControls/ComboBox.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_DefaultControls_ComboBox.xaml.html)
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DefaultControls/ScrollViewer.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_DefaultControls_ScrollViewer.xaml.html)
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DefaultControls/Slider.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_DefaultControls_Slider.xaml.html)
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DefaultControls/TextBox.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_DefaultControls_TextBox.xaml.html)
|
||||
A source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DefaultControls/ToggleButton.xaml
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DefaultControls/ToolTip.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_DefaultControls_ToolTip.xaml.html)
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DerivedStyles/ButtonBottomMenu.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_DerivedStyles_ButtonBottomMenu.xaml.html)
|
||||
D source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DerivedStyles/ButtonFilterNagivation.xaml
|
||||
D source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DerivedStyles/ButtonMainMenu.xaml
|
||||
D source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DerivedStyles/ButtonMessageBox.xaml
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DerivedStyles/ButtonTopMenu.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_DerivedStyles_ButtonTopMenu.xaml.html)
|
||||
D source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DerivedStyles/ButtonVirtualKeyboard.xaml
|
||||
D source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DerivedStyles/CheckBoxSettings.xaml
|
||||
D source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DerivedStyles/ListGameItem.xaml
|
||||
A source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DerivedStyles/ListGameItemStyle.xaml
|
||||
A source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DerivedStyles/ListGameItemTemplate.xaml
|
||||
D source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DerivedStyles/MainWindowStyle.xaml
|
||||
D source/Playnite.FullscreenApp/Themes/Fullscreen/Default/DerivedStyles/ToggleButtonTopFilter.xaml
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Images/ButtonPrompts/PlayStation/PlayStation.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_Images_ButtonPrompts_PlayStation_PlayStation.xaml.html)
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Images/ButtonPrompts/Xbox/Xbox.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_Images_ButtonPrompts_Xbox_Xbox.xaml.html)
|
||||
A source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/ActionSelection.xaml
|
||||
D source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/Filters.xaml
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/FiltersAdditional.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_Views_FiltersAdditional.xaml.html)
|
||||
A source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/FiltersView.xaml
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/GameDetails.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_Views_GameDetails.xaml.html)
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/GameMenu.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_Views_GameMenu.xaml.html)
|
||||
A source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/GameStatus.xaml
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/Main.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_Views_Main.xaml.html)
|
||||
[M source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/MainMenu.xaml](https://playnite.link/themechangelog/1.9.0-2.0.0/Playnite.FullscreenApp_Themes_Fullscreen_Default_Views_MainMenu.xaml.html)
|
||||
A source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/MessageBox.xaml
|
||||
D source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/Notifications.xaml
|
||||
A source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/NotificationsMenu.xaml
|
||||
D source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/SettingsMenu.xaml
|
||||
A source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/SettingsMenus.xaml
|
||||
A source/Playnite.FullscreenApp/Themes/Fullscreen/Default/Views/TextInput.xaml
|
||||
D source/Playnite.FullscreenApp/Themes/Fullscreen/DefaultLime/Constants.xaml
|
||||
@ -1,70 +0,0 @@
|
||||
# Distributing Themes
|
||||
|
||||
Introduction
|
||||
---------------------
|
||||
|
||||
You should only distribute files that your theme changes compared to the original source theme. It's because of the way theme loading is implemented in Playnite. Playnite is capable of loading only modified files while keeping everything else from original theme. This is to make sure that when change is made to original files, those changes are also applied to custom themes as well (unless custom theme provides their own version of that file).
|
||||
|
||||
This is done for a reason that theme files can contain functional elements (like buttons), that add or remove functionality and this makes sure that new functionality is also available in custom themes if possible.
|
||||
|
||||
If you distribute all files with your theme (even those you didn't modify) and update is made to Playnite that adds new functionality via theme files, your theme users won't be able to use that new functionality until you update the theme.
|
||||
|
||||
Packaging themes
|
||||
---------------------
|
||||
|
||||
To package theme, run [Toolbox](../toolbox.md) utility with following arguments:
|
||||
|
||||
```cmd
|
||||
Toolbox.exe pack <ThemeDirectoryPath> <TargetFolder>
|
||||
```
|
||||
|
||||
For example...
|
||||
|
||||
```cmd
|
||||
Toolbox.exe pack "c:\playnite\Themes\Desktop\Default\TestingTheme" "c:\somedir"
|
||||
```
|
||||
|
||||
...will create `c:\somedir\SuperClearModern.pthm` theme file you can distribute to users.
|
||||
|
||||
`<ThemeDirectoryPath>` is full path to folder where you are developing the theme.
|
||||
|
||||
Uploading themes
|
||||
---------------------
|
||||
|
||||
The best place to share themes is via [Playnite add-on database](https://github.com/JosefNemec/PlayniteAddonDatabase), submitting a theme there will make it available in Playnite's built-in add-on browser and will also enable easy theme installation and updates.
|
||||
|
||||
It's also recommended to submit theme entry to official Playnite forum, specifically [add-on database](https://playnite.link/forum/forum-3.html) sub-forum.
|
||||
|
||||
Updating themes
|
||||
---------------------
|
||||
|
||||
You will need to update themes from time to time to make sure they work with new Playnite versions properly. You can follow changes to theme files by subscribing to [change tracking GitHub issue](https://github.com/JosefNemec/Playnite/issues/1259).
|
||||
|
||||
> [!WARNING]
|
||||
> Keeping your theme update is essential if you want theme users to take advantage of newly added Playnite features and fixes.
|
||||
|
||||
Updates are necessary in these two cases:
|
||||
|
||||
* Theme API is updated with breaking changes (major version number changes, for example from `1.0.0` to `2.0.0`).
|
||||
* Playnite will not load themes that are not made for supported API version.
|
||||
* Minor updates will not break theme loading. For example Theme made for version `1.0.0` will still load in Playnite with API version `1.5.0`.
|
||||
|
||||
* New functionality is added to Playnite that requires update in theme file.
|
||||
* This usually means that your theme will still work (unless update means breaking change to Theme API), but users won't be able to make use of new features until the theme is updated.
|
||||
|
||||
You generally don't need to update your theme if you didn't modify any files mentioned in the changelog for a specific version and you are packaging your theme using Toolbox utility.
|
||||
|
||||
Blend made themes
|
||||
---------------------
|
||||
|
||||
`Toolbox` utility can be used to automatically update theme files if you are developing themes in Blend.
|
||||
|
||||
To update existing theme run Toolbox with following arguments:
|
||||
|
||||
```cmd
|
||||
Toolbox.exe update "<ThemeDirectoryPath>"
|
||||
```
|
||||
|
||||
`<ThemeDirectoryPath>` is full path to folder where you are developing the theme.
|
||||
|
||||
Toolbox will try to update all files to latest version, but if you modified files that were also modified in the latest API change, you will need to update those files manually. You will get the list of all files requiring manual update after the update process is finished.
|
||||
@ -1,47 +0,0 @@
|
||||
Integrating extension elements
|
||||
=====================
|
||||
|
||||
Introduction
|
||||
---------------------
|
||||
|
||||
If an extension use Playnite SDK to officially expose its custom UI elements, then you can use following markups to more easily integrate those elements. This requires proper support for specific extension, it's not something that's generally enabled by default on all extensions. You should contact extension developer for support in case you have issue integrating specific element.
|
||||
|
||||
Integrating elements
|
||||
---------------------
|
||||
|
||||
To actually use plugin control in a view, add `ContentControl` with its name set in `<SourceName>_<ElementName>` format:
|
||||
|
||||
- `SourceName` is plugin's source name.
|
||||
- `ElementName` is a specific element name you want to integrate.
|
||||
|
||||
Both of these should be provided by an extension developer.
|
||||
|
||||
For example, to include `TestUserControl1` control from `TestPlugin` source:
|
||||
|
||||
```xml
|
||||
<ContentControl x:Name="TestPlugin_TestUserControl1" />
|
||||
```
|
||||
|
||||
Detecting if an extension is installed
|
||||
---------------------
|
||||
|
||||
You can use `PluginStatus` markup to add conditions based on if a plugin is installed or not.
|
||||
|
||||
```xml
|
||||
<SomeElement Property="{PluginStatus Plugin=AddonId, Status=Installed}" />
|
||||
```
|
||||
|
||||
`PluginStatus` automatically converts to `Visibility` value if used on Visibility property, it's not needed to use converter in that case. In other cases it return's `bool` value, `true` if a plugin is installed.
|
||||
|
||||
`AddonId` should be provided by extension's developer.
|
||||
|
||||
Extension settings
|
||||
---------------------
|
||||
|
||||
If an extension provides support for themes to use its settings, then you can use `PluginSettings` markup to reference them:
|
||||
|
||||
```xml
|
||||
<TextBlock Text="{PluginSettings Plugin=<SourceName>, Path=CustomOption}" />
|
||||
```
|
||||
|
||||
where `SourceName` is the plugin source name and `CustomOption` is the name of a specific settings property (or path in case you want to reference nested properties).
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 546 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.9 KiB |
@ -1,17 +0,0 @@
|
||||
# Installing themes
|
||||
|
||||
Using .pthm file
|
||||
---------------------
|
||||
|
||||
If theme developer distributes the theme as `.pthm` file then just drag and drop the file to Playnite's main window while it's running in Desktop mode. You will be prompted with installation dialog and after installation is complete you can change to new theme via Settings menu.
|
||||
|
||||
Manual installation
|
||||
---------------------
|
||||
|
||||
### Standard Playnite installation
|
||||
|
||||
Copy theme folder into `%AppData%\Playnite\Themes\Desktop|Fullscreen` directory.
|
||||
|
||||
### Portable Playnite installation
|
||||
|
||||
Copy theme folder into `\Themes\Desktop|Fullscreen` folder inside Playnite's installation directory.
|
||||
@ -1,71 +0,0 @@
|
||||
# Introduction to Themes
|
||||
|
||||
General information
|
||||
---------------------
|
||||
|
||||
Playnite's user interface is implemented using Windows Presentation Framework (WPF) and UI definition is done using [XAML](https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/xaml-overview-wpf) files. Custom themes in Playnite are implemented using [standard template and styling](https://docs.microsoft.com/en-us/dotnet/framework/wpf/controls/styling-and-templating) support that WPF provides, therefore any tutorial that applies to styling in WPF also applies to Playnite.
|
||||
|
||||
Fullscreen and Desktop modes
|
||||
---------------------
|
||||
|
||||
Playnite offers two separate modes of operation. Standard `Desktop` mode designed for keyboard and mouse and `Fullscreen` mode designed to be controlled with gamepad. These two modes are implemented completely separately and therefore themes are also completely separate.
|
||||
|
||||
Learning resources
|
||||
---------------------
|
||||
|
||||
Since Playnite themes are essentially just set of [template and style](https://docs.microsoft.com/en-us/dotnet/framework/wpf/controls/styling-and-templating) files, general editing rules and tutorials that apply to WPF also apply to Playnite.
|
||||
|
||||
Recommended WPF resources:
|
||||
* https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/xaml-overview-wpf
|
||||
* https://www.wpftutorial.net/GettingStarted.html
|
||||
* https://www.tutorialspoint.com/wpf/
|
||||
|
||||
> [!NOTE]
|
||||
> There's currently very active community around theme/extension development on our [Discord server](https://discord.gg/hSFvmN6). We highly recommend joining if you plan to develop add-ons for Playnite!
|
||||
|
||||
Creating Playnite themes
|
||||
---------------------
|
||||
|
||||
> [!WARNING]
|
||||
> Do not edit built-in default themes. Always create new copy of theme files (ideally using Toolbox utility) are edit those. Broken edits to default theme files could lead to Playnite not being able to start anymore.
|
||||
|
||||
> [!WARNING]
|
||||
> Please read the documentation carefully, especially section about [distribution and theme updates](distributionAndUpdates.md). Not updating your theme regularly could cause issues to theme users, for example they might not be able to use newly added features. Or they might not be able to load the theme at all in newer version of Playnite, in the worst case scenario.
|
||||
|
||||
There are generally two approaches to theme creation in Playnite.
|
||||
|
||||
1. **[Manually editing](manualEditing.md)** XAML files using any text editor.
|
||||
|
||||
2. **[Using Blend/Visual Studio](usingBlend.md)** designer.
|
||||
|
||||
Option #1 doesn't require installation of any additional applications and themes can be generally created even using Notepad. However this approach has major disadvantages:
|
||||
* You don't get live preview of changes your are making.
|
||||
* You have to restart Playnite every time a change is made to theme files.
|
||||
* There's not autocompletion or error checking for XAML syntax.
|
||||
|
||||
Option #2 requires installation of [Visual Studio IDE](https://visualstudio.microsoft.com/), Community edition is free to download and includes [Blend](https://docs.microsoft.com/en-us/visualstudio/designers/creating-a-ui-by-using-blend-for-visual-studio?view=vs-2019) editor. This approach takes some time to set up, but offers all advantages that manual editing lacks, like live preview, autocompletion of XAML properties, visual editor etc.
|
||||
|
||||
**Using Blend editor is recommended option.**
|
||||
|
||||
> [!WARNING]
|
||||
> Theme installation and update always replaces the entire theme directory completely. Meaning that any files that are not part of the installation package will be lost during installation process! If your theme includes some custom functionality that requires user to replace/add files to theme's directory, make sure they know that they will loose those changes after an update!
|
||||
|
||||
Integrating with plugins
|
||||
---------------------
|
||||
|
||||
Plugins can provide custom UI elements that can be integration into a theme. See [extension integration page](extensionIntegration.md) for more details.
|
||||
|
||||
Theme files and directories
|
||||
---------------------
|
||||
|
||||
This section explains contents and purpose of specific theme files.
|
||||
|
||||
| Directory/File | Description |
|
||||
| -- | -- |
|
||||
| DefaultControls | Styles for standard (built-in WPF) controls like button, checkbox etc. |
|
||||
| DerivedStyles | Styles for standard (built-in WPF) controls like button, checkbox etc., that are used in specific cases. For example Play button, list item for Grid view etc. |
|
||||
| CustomControls | Styles for custom Playnite controls. |
|
||||
| Views | Styles for library views and panels. |
|
||||
| Common.xaml | Base styles that are inherited by other styles from the theme. |
|
||||
| Constants.xaml | Colors, brushes, sizes and other constants used by styles form the theme. |
|
||||
| Media.xaml | Various icons, texts and image specifications used by styles form the theme. |
|
||||
@ -1,23 +0,0 @@
|
||||
# Theme manifest file
|
||||
|
||||
General information
|
||||
---------------------
|
||||
|
||||
Every theme has to have manifest file name `theme.yaml`. This file is used by Playnite for several things including loading the theme and theme will not be usable in Playnite if manifest file is missing. The file should be in theme's root directory.
|
||||
|
||||
Available fields
|
||||
---------------------
|
||||
|
||||
| Field | Description |
|
||||
| -- | -- |
|
||||
| Id | Unique string identifier for the theme. Must not be shared with any other theme. |
|
||||
| Name | Theme's name that will be displayed during installation and on theme selection dialogs. |
|
||||
| Author | Name of theme's author. |
|
||||
| Version | Extension version, must be a valid [.NET version string](https://docs.microsoft.com/en-us/dotnet/api/system.version). |
|
||||
| Mode | Specifies whether the theme is for Desktop of Fullscreen mode. |
|
||||
| ThemeApiVersion | Theme API version required for theme to work. |
|
||||
| Links | Optional list of links (extension website, changelog etc.) |
|
||||
|
||||
|
||||
> [!WARNING]
|
||||
> Fields `Mode` and `ThemeApiVersion` are automatically generated and shouldn't be changed by hand, unless you are updating the theme to support newer versions of Playnite.
|
||||
@ -1,28 +0,0 @@
|
||||
# Creating themes manually
|
||||
|
||||
Basics
|
||||
---------------------
|
||||
|
||||
This method is generally not recommended and we recommend using [Blend](usingBlend.md) instead. However for smaller changes this is a usable method.
|
||||
|
||||
Creating theme
|
||||
---------------------
|
||||
|
||||
* Create empty folder inside of `Themes` directory (and `Fullscreen` or `Desktop` subdirectory).
|
||||
* Create theme [manifest file](manifestFile.md).
|
||||
* Set proper `Mode` and `ThemeApiVersion` fields. `ThemeApiVersion` of currently installed Playnite version can be found by opening `About Playnite` menu from Desktop mode.
|
||||
* Copy original theme file you want to edit (xaml, image etc.) to the new folder (make sure you keep the directory structure).
|
||||
* Make changes to copied file using any text editor.
|
||||
|
||||
Testing changes
|
||||
---------------------
|
||||
|
||||
To test theme in Playnite itself, just start Playnite and change theme selection in the application settings. No additional steps should be needed for Playnite to load the theme as long as theme manifest is present.
|
||||
|
||||
Packaging theme for distribution
|
||||
---------------------
|
||||
|
||||
See [Distribution and Updates](distributionAndUpdates.md) page for more details.
|
||||
|
||||
> [!WARNING]
|
||||
> Please pay special attention to section about updating themes to make sure your custom theme always works with the latest Playnite version.
|
||||
@ -1,112 +0,0 @@
|
||||
# Creating themes using Blend editor
|
||||
|
||||
Installing Blend
|
||||
---------------------
|
||||
|
||||
Blend is part of [Visual Studio IDE](https://visualstudio.microsoft.com/), which is available for free with Community edition. Visual Studio comes with lot of components you might not be interested in, for theme development you only need `.NET Desktop development` workload.
|
||||
|
||||
> [!NOTE]
|
||||
> Couple people reported that live preview doesn't work properly in Visual Studio 2022, therefore 2019 or 2017 version is recommended.
|
||||
|
||||
Creating new theme
|
||||
---------------------
|
||||
[Open command prompt](https://www.windows-commandline.com/how-to-open-command-prompt/) and [navigate](https://www.windows-commandline.com/command-prompt-change-directory/) to Playnite's installation folder. To create new theme you need to run `Toolbox.exe` utility with these arguments:
|
||||
|
||||
```cmd
|
||||
Toolbox.exe new desktoptheme|fullscreentheme <ThemeName>
|
||||
```
|
||||
|
||||
For example to create new desktop theme with "Super Clear Modern" name:
|
||||
|
||||
```cmd
|
||||
Toolbox.exe new desktoptheme "Super Clear Modern"
|
||||
```
|
||||
|
||||
This will create new theme folder with all files needed for theme to be edited in Blend. If theme creation is successful then Explorer window will open with your new theme folder. DO NOT move theme's directory, designer in Blend will not work properly unless the theme is opened from the location where Toolbox created it!
|
||||
|
||||
> [!NOTE]
|
||||
> There might be issues with above examples if you installed Playnite into folder where write access is not enabled by default unless you have elevated privileges (folders like `c:\Program Files`). In that case you will need to run command prompt and Blend with admin privileges. However better approach would be to use different install location.
|
||||
|
||||
Editing theme
|
||||
---------------------
|
||||
|
||||
To edit theme in Blend open `Theme.sln` file from theme's directory.
|
||||
|
||||
> [!NOTE]
|
||||
> Just opening `.sln` file will usually open Visual Studio instead of Blend. While you can use Visual Studio to edit the theme as well, it lacks many features that make editing easier, like live preview for templates and styles. To open `.sln` files in Blend, right-click on the file, select `Open with` and choose `Blend for Visual Studio` option.
|
||||
|
||||
> [!WARNING]
|
||||
> Due to way Playnite resolves paths to theme files (like images), it is necessary to open theme sln file via the file itself. If you open Blend first and then use it to open the theme sln, some parts of live preview might not work properly. This will be fixed in future Playnite updates.
|
||||
|
||||
As a first thing after creating new theme, open `theme.yaml` file and change manifest fields if you need to (you will probably need to change Author at least). For more information about available manifest fields see [manifest file page](manifestFile.md).
|
||||
|
||||
Files
|
||||
---------------------
|
||||
|
||||
Themes consist of several `.xaml` files. Each view, panel or specific control usually has their own xaml file. Commonly used resources like colors and brushes that affect all controls are generally defined in `Constants.xaml`.
|
||||
|
||||
Live preview
|
||||
---------------------
|
||||
|
||||
To open live preview (design view):
|
||||
|
||||
#### 1) Open appropriate style (xaml) file
|
||||
|
||||
Not all files can be previewed in design view, some only contain constants like colors, brushes etc. `Constants.xaml` is best example of this. If you want to see preview for these resources, open resources window (View -> Resources window) and expand appropriate file.
|
||||
|
||||
#### 2) Open design view panel
|
||||
|
||||
Toggle design view using `Design` tab button. It is highly recommended to keep XAML text view open as well since it's faster for making changes. To have both views open you can split the editor using buttons on bottom right part of the editor (offering both horizontal and vertical split.
|
||||
|
||||

|
||||
|
||||
#### 3) Select style to preview
|
||||
|
||||
Since single xaml file can contain multiple styles for multiple views/controls, you need to select style you want to preview first. To do so select line in a text editor starting with with `<Style TargetType=...`.
|
||||
|
||||
#### 4) Activate preview
|
||||
|
||||
On design panel select `Style` dropdown, then `Edit Template` and lastly `Edit Current`. This will load preview for style you selected in previous step.
|
||||
|
||||

|
||||
|
||||
#### 5) Enjoy
|
||||
|
||||
Now a preview for the specific view/control should be visible. If the view doesn't seem to display all resources properly (for example missing or incorrect colors and brushes are used), see troubleshooting section.
|
||||
|
||||

|
||||
|
||||
Troubleshooting
|
||||
---------------------
|
||||
|
||||
### Fonts, colors and other resources are not applied
|
||||
|
||||
Opening style's design view for the first sometimes doesn't properly load referenced resources (like fonts, colors etc). This is a Blend issue and can be fixed easily by editing some part of the style, which will force the design view to reload. Switching to a different file tab and back also resolves this sometimes.
|
||||
|
||||
### Updating ThemeFile markup doesn't update in a preview
|
||||
|
||||
Specifically declare `RelativePath` property if this happens:
|
||||
```xml
|
||||
<Image Source="{ThemeFile RelativePath='Images/applogo.png'}" />
|
||||
```
|
||||
...instead of just:
|
||||
```xml
|
||||
<Image Source="{ThemeFile 'Images/applogo.png'}" />
|
||||
```
|
||||
|
||||
### Design view just doesn't work
|
||||
|
||||
This happens if theme is not opened from correct directory. As mentioned above, theme's .sln file must be opened from the directory that Toolbox created it in. Moving to a different directory will cause issues!
|
||||
|
||||
Testing changes
|
||||
---------------------
|
||||
|
||||
To test theme in Playnite itself, just start Playnite and change theme selection in the application settings. No additional steps should be needed for Playnite to load the theme.
|
||||
|
||||
Packaging theme for distribution
|
||||
---------------------
|
||||
|
||||
See [Distribution and Updates](distributionAndUpdates.md) page for more details.
|
||||
|
||||
> [!WARNING]
|
||||
> Please pay special attention to section about updating themes to make sure your custom theme always works with the latest Playnite version.
|
||||
@ -1,90 +0,0 @@
|
||||
Referencing theme files
|
||||
---------------------
|
||||
|
||||
If you need to reference a file that's part of you theme (for example an image), then you need to use `ThemeFile` markup extension.
|
||||
|
||||
For example creating image that uses `applogo.png` file stored in `Images` subfolder would be done this way:
|
||||
|
||||
```xml
|
||||
<Image Source="{ThemeFile 'Images/applogo.png'}" />
|
||||
```
|
||||
|
||||
If you need to reference theme files based on game property, use `ThemeFileBinding` markup extension.
|
||||
|
||||
For example to bind to an image based on game's platform name:
|
||||
```xml
|
||||
<Image Source="{ThemeFileBinding Game.Platform.Name, PathFormat='Platforms/{0}.jpg'}" />
|
||||
```
|
||||
|
||||
Adding video to a theme
|
||||
---------------------
|
||||
|
||||
Use [MediaElement](https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.mediaelement?view=netframework-4.8) element ([supported formats](https://docs.microsoft.com/en-us/previous-versions/windows/silverlight/dotnet-windows-silverlight/cc189080(v=vs.95)?redirectedfrom=MSDN)) to add a video to a xaml file. Video files by default don't repeat, to automatically repeat playback use `MediaElementBehaviors.Repeat` behavior.
|
||||
|
||||
Following example adds video file `video.mp4` stored in `Videos` theme subfolder and plays it on repeat:
|
||||
|
||||
```xml
|
||||
<MediaElement Source="{ThemeFile 'Videos/video.mp4'}" MediaElementBehaviors.Repeat="True" />
|
||||
```
|
||||
|
||||
What all these PART_ element names
|
||||
---------------------
|
||||
|
||||
You may have seen something like this in theme files:
|
||||
|
||||
```xml
|
||||
<CheckBox x:Name="PART_ToggleFilter" />
|
||||
```
|
||||
|
||||
This notifies theme engine about what kind of checkbox it is and how to hookup functionality for it. If the name is changed or removed then the element will loose all functionality and you will need to set it up in theme file itself via `Binding` markups. You can see PART specifications in appropriate backend file for each control/view (for example [this file](https://github.com/JosefNemec/Playnite/blob/master/source/Playnite.DesktopApp/Controls/Views/GameOverview.cs) for GameOverview view).
|
||||
|
||||
This however doesn't mean that you can only include information backed by PART definition in your themes...
|
||||
|
||||
Custom mouse cursor
|
||||
---------------------
|
||||
|
||||
Custom mouse cursors are only supported in `.cur` and `.ani` formats. To assign custom cursor to a theme, put `cursor.cur` or `cursor.ani` file into theme directory root (next to `theme.yaml` file).
|
||||
|
||||
Changing audio files
|
||||
---------------------
|
||||
|
||||
All audio files must be stored in `audio` sub-directory and have **44.1 kHz** sampling rate!
|
||||
|
||||
You can currently change several audio samples in Fullscreen themes:
|
||||
|
||||
| Type | File name | Supported formats |
|
||||
| :--- | :--- | :--- |
|
||||
| Navigation sound | navigation | `.wav`, `.mp3` |
|
||||
| Activation sound | activation | `.wav`, `.mp3` |
|
||||
| Background sound/music | background | `.wma`, `.mp3` |
|
||||
|
||||
|
||||
Adding additional information to views
|
||||
---------------------
|
||||
|
||||
Not every information, that is available to theme, is always displayed on screen and you may want to display it in your custom theme or completely change how the original information is displayed using PART system. For example `GameDetails.xaml` view from Fullscreen mode theme only shows some game information.
|
||||
|
||||
You can display additional information by adding extra elements (TextBoxes, Images etc.) and binding source data to it. When using Blend you can easily see what information is available on particular view by starting typing `Binding` markup, the list of available fields should show up like this:
|
||||
|
||||

|
||||
|
||||
If it doesn't then you can invoke it via `CTRL-Space` shortcut after typing `Binding`.
|
||||
|
||||
Useful data binding docs:
|
||||
* https://www.wpf-tutorial.com/data-binding/introduction/
|
||||
* https://docs.microsoft.com/en-us/dotnet/framework/wpf/data/data-binding-wpf
|
||||
|
||||
Color definitions
|
||||
---------------------
|
||||
|
||||
You may be wondering why are some colors defined with just 6 digits like `#112233` and other with 8 digits like `#BB112233`. WPF uses RGB system to define color values where each color is defined by values ranging from `00` to `FF` (using [hex](https://simple.wikipedia.org/wiki/Hexadecimal_numeral_system) digits): `#RRGGBB`. However you can also define alpha transparency using additional two digits to specify transparency intensity: `#AARRGGBB`. Where `00` is fully transparent and `FF` is fully opaque.
|
||||
|
||||
Using custom controls and 3rd party assemblies
|
||||
---------------------
|
||||
|
||||
The way Playnite currently loads theme files doesn't natively support use of 3rd party assemblies unless they are manually placed in application folder, meaning they can't be distributed inside [pthm](distributionAndUpdates.md) files.
|
||||
|
||||
Using custom fonts
|
||||
---------------------
|
||||
|
||||
Limitations of using 3rd party assemblies also apply to use of custom fonts. Currently recommended option is to install desired font in Windows font storage and then use it as any other built-in Windows font in your XAML files.
|
||||
@ -1,64 +0,0 @@
|
||||
- name: Extensions
|
||||
items:
|
||||
- name: Introduction
|
||||
href: extensions/intro.md
|
||||
- name: Scripts
|
||||
href: extensions/scripting.md
|
||||
- name: Plugins
|
||||
href: extensions/plugins.md
|
||||
- name: Library Plugins
|
||||
href: extensions/libraryPlugins.md
|
||||
- name: Metadata Plugins
|
||||
href: extensions/metadataPlugins.md
|
||||
- name: Data directories
|
||||
href: extensions/dataDirectory.md
|
||||
- name: Logging
|
||||
href: extensions/logging.md
|
||||
- name: Plugin settings
|
||||
href: extensions/pluginSettings.md
|
||||
- name: Working with game library
|
||||
href: extensions/library.md
|
||||
- name: Events
|
||||
href: extensions/events.md
|
||||
- name: UI Interaction
|
||||
href: extensions/ui.md
|
||||
- name: Custom UI Integration
|
||||
href: extensions/customUiIntegration.md
|
||||
- name: Menu items
|
||||
href: extensions/menus.md
|
||||
- name: Game actions
|
||||
href: extensions/gameActions.md
|
||||
- name: Custom windows
|
||||
href: extensions/windows.md
|
||||
- name: Game variables
|
||||
href: extensions/expandingVariables.md
|
||||
- name: Playnite URI support
|
||||
href: extensions/uriSupport.md
|
||||
- name: Debugging scripts
|
||||
href: extensions/scriptingDebugging.md
|
||||
- name: String localizations
|
||||
href: extensions/localizations.md
|
||||
- name: Manifest file
|
||||
href: extensions/extensionsManifest.md
|
||||
|
||||
- name: Themes
|
||||
items:
|
||||
- name: Introduction
|
||||
href: themes/introduction.md
|
||||
- name: Using Blend
|
||||
href: themes/usingBlend.md
|
||||
- name: Manual editing
|
||||
href: themes/manualEditing.md
|
||||
- name: Distribution and updates
|
||||
href: themes/distributionAndUpdates.md
|
||||
- name: Various
|
||||
href: themes/various.md
|
||||
- name: Installing themes
|
||||
href: themes/installing.md
|
||||
- name: Manifest file
|
||||
href: themes/manifestFile.md
|
||||
- name: Extension integrations
|
||||
href: themes/extensionIntegration.md
|
||||
|
||||
- name: Toolbox utility
|
||||
href: toolbox.md
|
||||
@ -1,88 +0,0 @@
|
||||
# Extension Toolbox utility
|
||||
|
||||
Introduction
|
||||
---------------------
|
||||
|
||||
Toolbox is Playnite utility that can be used for various tasks, mainly for creating extensions and themes. Toolbox is distributed with every Playnite installation and can be found in Playnite's installation directory.
|
||||
|
||||
Creating new extensions
|
||||
---------------------
|
||||
|
||||
### Themes
|
||||
|
||||
```cmd
|
||||
Toolbox.exe new <themetype> <themename>
|
||||
```
|
||||
|
||||
`<themetype>` available options:
|
||||
- **DesktopTheme**
|
||||
- **FullscreenTheme**
|
||||
|
||||
`<themename>` - name of the theme.
|
||||
|
||||
#### Example
|
||||
|
||||
```cmd
|
||||
Toolbox.exe new desktoptheme "New Desktop Theme"
|
||||
```
|
||||
|
||||
### Scripts
|
||||
|
||||
```cmd
|
||||
Toolbox.exe new <scripttype> <scriptname> <targetfolder>
|
||||
```
|
||||
|
||||
`<scripttype>` available options:
|
||||
- **PowerShellScript**
|
||||
|
||||
`<scriptname>` - name of the new script extension.
|
||||
|
||||
`<targetfolder>` - folder to create script in.
|
||||
|
||||
#### Example
|
||||
|
||||
```cmd
|
||||
Toolbox.exe new PowerShellScript "Testing Script" "d:\somefolder"
|
||||
```
|
||||
|
||||
### Plugins
|
||||
|
||||
```cmd
|
||||
Toolbox.exe new <plugintype> <pluginname> <targetfolder>
|
||||
```
|
||||
|
||||
`<plugintype>` available options:
|
||||
- **GenericPlugin**
|
||||
- **MetadataPlugin**
|
||||
- **LibraryPlugin**
|
||||
|
||||
`<pluginname>` - name of the new plugin extension.
|
||||
|
||||
`<targetfolder>` - folder to create plugin in.
|
||||
|
||||
#### Example
|
||||
|
||||
```cmd
|
||||
Toolbox.exe new MetadataPlugin "GameDatabase metadata provider" "d:\somefolder"
|
||||
```
|
||||
|
||||
Packing extensions
|
||||
---------------------
|
||||
|
||||
```cmd
|
||||
Toolbox.exe pack <extensionfolder> <targetfolder>
|
||||
```
|
||||
|
||||
`<extensionfolder>` - extension directory (theme, script or plugin) to pack (in case of plugins it has to be folder with built binaries).
|
||||
|
||||
`<targetfolder>` - target directory where to save packed file.
|
||||
|
||||
#### Example
|
||||
|
||||
```cmd
|
||||
Toolbox.exe pack "C:\Playnite\Themes\Fullscreen\TestingFullscreen" "c:\somefolder"
|
||||
```
|
||||
|
||||
... will create `c:\somefolder\TestingFullscreen.pthm` package.
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
references/CefSharpRedist/vcruntime140_threads.dll
Normal file
BIN
references/CefSharpRedist/vcruntime140_threads.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
references/SDL2.dll
Normal file
BIN
references/SDL2.dll
Normal file
Binary file not shown.
BIN
references/SDL2_mixer.dll
Normal file
BIN
references/SDL2_mixer.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,12 +1,14 @@
|
||||
using Playnite.DesktopApp.ViewModels;
|
||||
using Playnite.SDK;
|
||||
using Playnite.SDK.Models;
|
||||
using Playnite.SDK.Plugins;
|
||||
using Playnite.ViewModels;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Playnite.DesktopApp.API
|
||||
{
|
||||
@ -19,20 +21,49 @@ namespace Playnite.DesktopApp.API
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mainModel.SelectedGames == null && mainModel.SelectedGame != null)
|
||||
return UIDispatcher.Invoke(() =>
|
||||
{
|
||||
return new List<Game>() { mainModel.SelectedGame.Game };
|
||||
}
|
||||
else
|
||||
{
|
||||
return mainModel.SelectedGames?.Select(a => a.Game).ToList();
|
||||
}
|
||||
if (mainModel.SelectedGames == null && mainModel.SelectedGame != null)
|
||||
{
|
||||
return new List<Game>() { mainModel.SelectedGame.Game };
|
||||
}
|
||||
else
|
||||
{
|
||||
return mainModel.SelectedGames?.Select(a => a.Game).ToList();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public DesktopView ActiveDesktopView => (DesktopView)mainModel.AppSettings.ViewSettings.GamesViewType;
|
||||
public DesktopView ActiveDesktopView
|
||||
{
|
||||
get => mainModel.AppSettings.ViewSettings.GamesViewType;
|
||||
set => mainModel.AppSettings.ViewSettings.GamesViewType = value;
|
||||
}
|
||||
|
||||
public List<Game> FilteredGames => mainModel.GamesView.CollectionView.Cast<GamesCollectionViewEntry>().Select(a => a.Game).Distinct().ToList();
|
||||
public FullscreenView ActiveFullscreenView { get; } = FullscreenView.List;
|
||||
|
||||
public SortOrder SortOrder
|
||||
{
|
||||
get => mainModel.AppSettings.ViewSettings.SortingOrder;
|
||||
set => mainModel.AppSettings.ViewSettings.SortingOrder = value;
|
||||
}
|
||||
|
||||
public SortOrderDirection SortOrderDirection
|
||||
{
|
||||
get => mainModel.AppSettings.ViewSettings.SortingOrderDirection;
|
||||
set => mainModel.AppSettings.ViewSettings.SortingOrderDirection = value;
|
||||
}
|
||||
|
||||
public GroupableField Grouping
|
||||
{
|
||||
get => mainModel.AppSettings.ViewSettings.GroupingOrder;
|
||||
set => mainModel.AppSettings.ViewSettings.GroupingOrder = value;
|
||||
}
|
||||
|
||||
public List<Game> FilteredGames => UIDispatcher.Invoke(() => mainModel.GamesView.CollectionView.Cast<GamesCollectionViewEntry>().Select(a => a.Game).Distinct().ToList());
|
||||
|
||||
public Dispatcher UIDispatcher => PlayniteApplication.CurrentNative.Dispatcher;
|
||||
|
||||
public MainViewAPI(DesktopAppViewModel mainModel)
|
||||
{
|
||||
@ -66,5 +97,68 @@ namespace Playnite.DesktopApp.API
|
||||
{
|
||||
mainModel.SelectGames(gameIds);
|
||||
}
|
||||
|
||||
public void ApplyFilterPreset(Guid filterId)
|
||||
{
|
||||
mainModel.ApplyFilterPreset(filterId);
|
||||
}
|
||||
|
||||
public void ApplyFilterPreset(FilterPreset preset)
|
||||
{
|
||||
mainModel.ActiveFilterPreset = preset;
|
||||
}
|
||||
|
||||
public Guid GetActiveFilterPreset()
|
||||
{
|
||||
return mainModel.AppSettings.SelectedFilterPreset;
|
||||
}
|
||||
|
||||
public FilterPresetSettings GetCurrentFilterSettings()
|
||||
{
|
||||
return mainModel.AppSettings.FilterSettings.AsPresetSettings();
|
||||
}
|
||||
|
||||
public void OpenSearch(string searchTerm)
|
||||
{
|
||||
mainModel.OpenSearch(searchTerm);
|
||||
}
|
||||
|
||||
public void OpenSearch(SearchContext context, string searchTerm)
|
||||
{
|
||||
mainModel.OpenSearch(context, searchTerm);
|
||||
}
|
||||
|
||||
public bool? OpenEditDialog(Guid gameId)
|
||||
{
|
||||
var game = mainModel.Database.Games.Get(gameId);
|
||||
if (game is null)
|
||||
return null;
|
||||
|
||||
return mainModel.GamesEditor.EditGame(game);
|
||||
}
|
||||
|
||||
public bool? OpenEditDialog(List<Guid> gameIds)
|
||||
{
|
||||
var games = mainModel.Database.Games.Get(gameIds);
|
||||
if (!games.HasItems())
|
||||
return null;
|
||||
|
||||
return mainModel.GamesEditor.EditGames(games);
|
||||
}
|
||||
|
||||
public List<FilterPreset> GetSortedFilterPresets()
|
||||
{
|
||||
return mainModel.SortedFilterPresets.ToList();
|
||||
}
|
||||
|
||||
public List<FilterPreset> GetSortedFilterFullscreenPresets()
|
||||
{
|
||||
return mainModel.SortedFilterFullscreenPresets.ToList();
|
||||
}
|
||||
|
||||
public void ToggleFullscreenView()
|
||||
{
|
||||
throw new NotSupportedInDesktopException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,12 +6,17 @@
|
||||
<appSettings file="Common.config">
|
||||
</appSettings>
|
||||
<runtime>
|
||||
<enforceFIPSPolicy enabled="false" />
|
||||
<loadFromRemoteSources enabled="True" />
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.InteropServices.RuntimeInformation" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
@ -12,10 +12,11 @@
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Playnite;component/Localization/LocSource.xaml"/>
|
||||
<ResourceDictionary Source="GlobalResources.xaml" />
|
||||
<ResourceDictionary Source="ControlGalleryView.xaml" />
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/Constants.xaml" />
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/Common.xaml" />
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/Media.xaml" />
|
||||
|
||||
|
||||
<!--Default Controls-->
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/DefaultControls/Border.xaml" />
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/DefaultControls/TextBlock.xaml" />
|
||||
@ -66,6 +67,7 @@
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/CustomControls/SearchBox.xaml" />
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/CustomControls/TopPanelItem.xaml" />
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/CustomControls/PathSelectionBox.xaml" />
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/CustomControls/HotKeyBox.xaml" />
|
||||
|
||||
<!--Derived Styles-->
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/DerivedStyles/TextBlockGameScore.xaml" />
|
||||
@ -102,6 +104,7 @@
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/Views/LibraryListView.xaml" />
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/Views/Library.xaml" />
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/Views/MainWindow.xaml" />
|
||||
<ResourceDictionary Source="Themes/Desktop/Default/Views/SearchView.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
|
||||
182
source/Playnite.DesktopApp/ControlGalleryView.xaml
Normal file
182
source/Playnite.DesktopApp/ControlGalleryView.xaml
Normal file
@ -0,0 +1,182 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:pctrls="clr-namespace:Playnite.DesktopApp.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Style x:Key="ControlGalleryContentStyle" TargetType="{x:Type ContentControl}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ContentControl}">
|
||||
<DockPanel Background="{DynamicResource WindowBackgourndBrush}"
|
||||
d:DesignWidth="800" d:DesignHeight="700">
|
||||
<Menu DockPanel.Dock="Top">
|
||||
<MenuItem Header="_File">
|
||||
<MenuItem Header="_New" />
|
||||
<MenuItem Header="Open" IsEnabled="False" />
|
||||
<MenuItem Header="Save" IsChecked="True" IsCheckable="True"/>
|
||||
<Separator />
|
||||
<MenuItem Header="Exit">
|
||||
<MenuItem Header="Test" />
|
||||
<MenuItem Header="Test2" />
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Header="Test" IsEnabled="False">
|
||||
<MenuItem Header="_New" />
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Header="Test2" >
|
||||
<MenuItem Header="New" />
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
<TabControl TabStripPlacement="Top">
|
||||
<TabItem Header="Test">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Margin="10" Grid.Column="0">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="Button" HorizontalAlignment="Left" Margin="5">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Test1" />
|
||||
<Separator />
|
||||
<MenuItem Header="Test2">
|
||||
<MenuItem Header="Test1" />
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
</Button>
|
||||
<RepeatButton Content="RepeatButton" HorizontalAlignment="Left" Margin="5"
|
||||
ToolTip="Testing tooltip for a button"/>
|
||||
<ToggleButton Content="ToggleButton"
|
||||
HorizontalAlignment="Left" Margin="5" />
|
||||
</StackPanel>
|
||||
|
||||
<UniformGrid Columns="2">
|
||||
<CheckBox Content="TestCheckbox" IsChecked="True" HorizontalAlignment="Left" IsThreeState="True" Margin="5"/>
|
||||
<TextBlock VerticalAlignment="Center">
|
||||
<Hyperlink>
|
||||
Hyperlink Click here
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
</UniformGrid>
|
||||
<UniformGrid Columns="2">
|
||||
<ComboBox IsEditable="True" Text="Test2" Margin="5"
|
||||
HorizontalAlignment="Stretch"/>
|
||||
<ComboBox SelectedIndex="1" Margin="5"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ComboBoxItem Content="Test1"/>
|
||||
<ComboBoxItem Content="Test2"/>
|
||||
<ComboBoxItem Content="Test3"/>
|
||||
<ComboBoxItem Content="Test1"/>
|
||||
<ComboBoxItem Content="Test2"/>
|
||||
<ComboBoxItem Content="Test3"/>
|
||||
<ComboBoxItem Content="Test1"/>
|
||||
<ComboBoxItem Content="Test2"/>
|
||||
<ComboBoxItem Content="Test3"/>
|
||||
<ComboBoxItem Content="Test1"/>
|
||||
<ComboBoxItem Content="Test2"/>
|
||||
<ComboBoxItem Content="Test3"/>
|
||||
<ComboBoxItem Content="Test1"/>
|
||||
<ComboBoxItem Content="Test2"/>
|
||||
<ComboBoxItem Content="Test3"/>
|
||||
<ComboBoxItem Content="Test1"/>
|
||||
<ComboBoxItem Content="Test2"/>
|
||||
<ComboBoxItem Content="Test3"/>
|
||||
<ComboBoxItem Content="Test3"/>
|
||||
<ComboBoxItem Content="Test1"/>
|
||||
<ComboBoxItem Content="Test2"/>
|
||||
<ComboBoxItem Content="Test3"/>
|
||||
<ComboBoxItem Content="Test1"/>
|
||||
<ComboBoxItem Content="Test2"/>
|
||||
<ComboBoxItem Content="Test3"/>
|
||||
<ComboBoxItem Content="Test3"/>
|
||||
<ComboBoxItem Content="Test1"/>
|
||||
</ComboBox>
|
||||
</UniformGrid>
|
||||
<TextBlock Text="Test text just test text" Margin="5"/>
|
||||
<TextBox Text="Test text just test text" Margin="5" />
|
||||
<TextBox Height="50" TextWrapping="Wrap" AcceptsReturn="True" Text="This TextBox will allow the user to enter multiple lines of text. When the RETURN key is pressed,
|
||||
or when typed text reaches the edge of the text box, a new line is automatically inserted." VerticalScrollBarVisibility="Auto" Margin="5"/>
|
||||
<PasswordBox Password="test" Margin="5"/>
|
||||
<Expander Header="TestExpander" IsExpanded="True" Margin="5">
|
||||
<ListView Height="100"
|
||||
Name="listview"
|
||||
SelectedIndex="1" Margin="5">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" />
|
||||
<GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}" />
|
||||
<GridViewColumn Header="Mail" Width="150" DisplayMemberBinding="{Binding Mail}" />
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
<ListViewItem Content="Tea"></ListViewItem>
|
||||
<ListViewItem Content="Test"></ListViewItem>
|
||||
</ListView>
|
||||
</Expander>
|
||||
<ListBox SelectedIndex="1" Margin="5" Height="100">
|
||||
<ListBoxItem Content="ListItem 1" />
|
||||
<ListBoxItem Content="ListItem 2" />
|
||||
<ListBoxItem Content="ListItem 3" />
|
||||
<ListBoxItem Content="ListItem 1" />
|
||||
<ListBoxItem Content="ListItem 2" />
|
||||
<ListBoxItem Content="ListItem 3" />
|
||||
<ListBoxItem Content="ListItem 1" />
|
||||
<ListBoxItem Content="ListItem 2" />
|
||||
<ListBoxItem Content="ListItem 3" />
|
||||
</ListBox>
|
||||
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1">
|
||||
<pctrls:NullIntNumericBox Margin="5" />
|
||||
<pctrls:LongNumericBox Margin="5" />
|
||||
<pctrls:SearchBox Margin="5" />
|
||||
<pctrls:FilterSelectionBox Margin="5" />
|
||||
<pctrls:DdItemListSelectionBox Margin="5" />
|
||||
|
||||
<GroupBox Header="Test Groubox" Margin="5">
|
||||
<StackPanel>
|
||||
<ProgressBar Value="30" Margin="5" Width="342" Height="20" />
|
||||
<RadioButton Content="RadioButton1" IsChecked="True" GroupName="test" Margin="5"/>
|
||||
<RadioButton Content="RadioButton2" GroupName="test" Margin="5" />
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<TreeView Margin="5">
|
||||
<TreeViewItem Header="Level 1" IsExpanded="True">
|
||||
<TreeViewItem Header="Level 2.1" IsSelected="True" />
|
||||
<TreeViewItem Header="Level 2.2" IsExpanded="True" >
|
||||
<TreeViewItem Header="Level 3.1" />
|
||||
<TreeViewItem Header="Level 3.2" />
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Header="Level 2.2" IsExpanded="False" >
|
||||
<TreeViewItem Header="Level 3.1" />
|
||||
<TreeViewItem Header="Level 3.2" />
|
||||
</TreeViewItem>
|
||||
</TreeViewItem>
|
||||
</TreeView>
|
||||
|
||||
<ScrollViewer Width="100" Height="100"
|
||||
HorizontalScrollBarVisibility="Auto" Margin="5">
|
||||
<Viewbox Width="200" Height="200">
|
||||
<TextBlock Text="R" />
|
||||
</Viewbox>
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="Test2">
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</DockPanel>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@ -27,7 +27,7 @@
|
||||
|
||||
<Grid Margin="5">
|
||||
<DockPanel Visibility="{Binding IsUpdateListLoading, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">
|
||||
<StackPanel DockPanel.Dock="Bottom" HorizontalAlignment="Right">
|
||||
<StackPanel DockPanel.Dock="Bottom" HorizontalAlignment="Left">
|
||||
<Button Content="{DynamicResource LOCAddonUpdateAddons}" Margin="0,5,0,0"
|
||||
Visibility="{Binding IsUpdateAvailable, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
Command="{Binding UpdateAddonsCommand}"/>
|
||||
|
||||
@ -54,8 +54,12 @@
|
||||
</DockPanel>
|
||||
|
||||
<ListBox ItemsSource="{Binding OnlineAddonList}"
|
||||
SelectedItem="{Binding SelectedOnlineAddon}"
|
||||
Name="ListOnlineAddons" Grid.Column="0" Grid.Row="1"
|
||||
ScrollViewer.CanContentScroll="False"
|
||||
VirtualizingPanel.IsVirtualizing="True"
|
||||
VirtualizingPanel.VirtualizationMode="Recycling"
|
||||
VirtualizingPanel.ScrollUnit="Pixel"
|
||||
ScrollViewer.CanContentScroll="True"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
@ -76,7 +80,7 @@
|
||||
|
||||
<ScrollViewer Grid.Column="2" Grid.Row="1" Margin="15,0,5,0"
|
||||
HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel DataContext="{Binding SelectedItem, ElementName=ListOnlineAddons}"
|
||||
<StackPanel DataContext="{Binding SelectedOnlineAddon}"
|
||||
Visibility="{Binding SelectedItem, ElementName=ListOnlineAddons, Converter={StaticResource NullToVisibilityConverter}}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{DynamicResource LOCExtensionCreatedBy}" />
|
||||
@ -84,12 +88,12 @@
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,5,0,0">
|
||||
<TextBlock Text="Version:" />
|
||||
<TextBlock Text="{DynamicResource LOCExtensionVersion}" />
|
||||
<TextBlock Text="{Binding LatestPackage.Version}" FontWeight="Bold" Margin="5,0,0,0" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,5,0,0">
|
||||
<TextBlock Text="Updated:" />
|
||||
<TextBlock Text="{DynamicResource LOCExtensionUpdated}" />
|
||||
<TextBlock Text="{Binding LatestPackage.ReleaseDate, Converter={StaticResource NullableDateToStringConverter}}" FontWeight="Bold" Margin="5,0,0,0" />
|
||||
</StackPanel>
|
||||
|
||||
@ -106,22 +110,28 @@
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<Button HorizontalAlignment="Left" Margin="0,15,0,0"
|
||||
<StackPanel Orientation="Horizontal" Margin="0,15,0,0">
|
||||
<Button Margin="0,0,10,0"
|
||||
Command="{Binding Data.InstallAddonCommand, Source={StaticResource RootDataContext}}"
|
||||
CommandParameter="{Binding}"
|
||||
Visibility="{Binding IsQueuedForInstall, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">
|
||||
<Button.Style>
|
||||
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="Content" Value="{DynamicResource LOCAddonInstall}" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsInstalled}" Value="True">
|
||||
<Setter Property="Content" Value="{DynamicResource LOCAddonAlreadyInstalled}" />
|
||||
<Setter Property="IsEnabled" Value="False" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
IsEnabled="{Binding IsQueuedForInstall, Converter={StaticResource NegateConverter}}">
|
||||
<Button.Style>
|
||||
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="Content" Value="{DynamicResource LOCAddonInstall}" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsInstalled}" Value="True">
|
||||
<Setter Property="Content" Value="{DynamicResource LOCAddonReinstall}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
|
||||
<ComboBox MinWidth="100"
|
||||
ItemsSource="{Binding Data.AvailablePackages, Source={StaticResource RootDataContext}}"
|
||||
SelectedValue="{Binding Data.SelectedInstallPackage, Source={StaticResource RootDataContext}}"
|
||||
DisplayMemberPath="Version" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Text="{DynamicResource LOCAddonQueuedForInstall}"
|
||||
Margin="0,10,0,0" TextWrapping="Wrap"
|
||||
|
||||
@ -113,7 +113,7 @@
|
||||
|
||||
<TextBlock Margin="5,10,0,10" DockPanel.Dock="Bottom">
|
||||
<Hyperlink Command="{x:Static pcmd:GlobalCommands.NavigateUrlCommand}"
|
||||
CommandParameter="https://playnite.link/docs/{AppBranch}/tutorials/extensions/intro.html">
|
||||
CommandParameter="{}{DocsRootUrl}/tutorials/extensions/intro.html">
|
||||
<Run Text="{DynamicResource LOCSettingsCreateExtensions}" />
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
|
||||
@ -95,7 +95,7 @@
|
||||
|
||||
<TextBlock Margin="5,10,0,10" DockPanel.Dock="Bottom">
|
||||
<Hyperlink Command="{x:Static pcmd:GlobalCommands.NavigateUrlCommand}"
|
||||
CommandParameter="https://playnite.link/docs/{AppBranch}/tutorials/themes/introduction.html">
|
||||
CommandParameter="{}{DocsRootUrl}/tutorials/themes/introduction.html">
|
||||
<Run Text="{DynamicResource LOCSettingsCreateThemes}" />
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
|
||||
@ -174,6 +174,34 @@ namespace Playnite.DesktopApp.Controls
|
||||
}
|
||||
|
||||
UpdateTextStatus();
|
||||
|
||||
if (Template.FindName("Popup", this) is Popup popup)
|
||||
{
|
||||
popup.Opened += (_, __) =>
|
||||
{
|
||||
if (ShowSearchBox && TextSearchBox != null)
|
||||
{
|
||||
TextSearchBox.IsFocused = true;
|
||||
}
|
||||
};
|
||||
|
||||
popup.Closed += (_, __) =>
|
||||
{
|
||||
if (ShowSearchBox && TextSearchBox != null)
|
||||
{
|
||||
TextSearchBox.IsFocused = false;
|
||||
TextSearchBox.Text = string.Empty;
|
||||
}
|
||||
};
|
||||
|
||||
popup.PreviewKeyUp += (_, keyArgs) =>
|
||||
{
|
||||
if (keyArgs.Key == Key.Escape)
|
||||
{
|
||||
popup.IsOpen = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override void ClearButtonAction(RoutedEventArgs e)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user