mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
Compare commits
1554 Commits
0.3.2
...
4.9.1-comp
Author | SHA1 | Date | |
---|---|---|---|
8823ecd209 | |||
f7451d82a6 | |||
d188e968c6 | |||
f432af5bfe | |||
caf96212d0 | |||
22b2640e1a | |||
78837a4a2b | |||
f2ee7c922b | |||
f8b42cc35b | |||
71df55c815 | |||
af1399e005 | |||
f6de26f7ac | |||
7ea9b16b37 | |||
ff6b774687 | |||
9bdaefded9 | |||
4a88612693 | |||
f8a88c54ce | |||
df2049b751 | |||
dc9afeb213 | |||
13c1c108ea | |||
16ee66e6dc | |||
d563dd3146 | |||
65a17071d2 | |||
d993ce8b1a | |||
9c4a114c94 | |||
7062062ec5 | |||
be7c334a72 | |||
b5f267d3bb | |||
d0d89dd133 | |||
a0e8cb6b4c | |||
348e875969 | |||
be0fb682e0 | |||
ea8f14e41b | |||
a8a3f3aafe | |||
387376e5e0 | |||
80cefdcfda | |||
6a14110720 | |||
8bfe2bf04c | |||
bbf4b321d7 | |||
310c297a36 | |||
5d14cb7af8 | |||
48291506f5 | |||
b0badd0630 | |||
c5ef671e0c | |||
ffb97aaabc | |||
d05ff26930 | |||
535083205a | |||
9a8d283d27 | |||
1eb02e77e0 | |||
b271cf9d32 | |||
0a084122d3 | |||
a29e0325dd | |||
4ea010f168 | |||
b03ab12e45 | |||
9311b38747 | |||
2380ba4612 | |||
60e2f0183e | |||
8009f65ed0 | |||
393fca6aed | |||
f8abe91b83 | |||
27ab3e0ea8 | |||
1ca10f3e34 | |||
c1cd1adb08 | |||
1266b3f3fe | |||
5505e0d7b5 | |||
a469fc539a | |||
ef36585319 | |||
46214eef44 | |||
5f0b152427 | |||
cbc7664b78 | |||
39bc97a51c | |||
017e551a91 | |||
19dad7775c | |||
de15118872 | |||
bb81e1e0ab | |||
58b49fed85 | |||
6740e5fec7 | |||
fe9419fb8a | |||
ba93b05efa | |||
d154e77299 | |||
2f8073d548 | |||
1f0c1691be | |||
50eedd11e0 | |||
6f50628172 | |||
4256f2df8b | |||
344f7c33e4 | |||
39454bc13e | |||
fcffa55af1 | |||
b74afd1033 | |||
ff548589bc | |||
f2f80c4e7e | |||
381745dbf6 | |||
1b61bd9551 | |||
415fb73245 | |||
458d59b401 | |||
ffb24da135 | |||
436cec69c2 | |||
30e2a5428f | |||
1154ba5b14 | |||
ffd89dbdeb | |||
b61211b4cb | |||
30af0cbd9a | |||
349ef5be97 | |||
7e0bc1fd10 | |||
b7bd95dcc4 | |||
fde1ada699 | |||
7556c5f855 | |||
4505612f75 | |||
035767bbbb | |||
8e43958f3d | |||
2be20a9179 | |||
77f63359f6 | |||
b13822db8d | |||
35c524c604 | |||
8c4374825d | |||
687d08afa2 | |||
8616d36204 | |||
c22199b8eb | |||
1deaedb7da | |||
452a307b33 | |||
0db1abcd2e | |||
01c898b104 | |||
2344842163 | |||
b8e693c97d | |||
99e66cc317 | |||
18468c17f2 | |||
6f0d056059 | |||
6b05d0381e | |||
e8c4d2b550 | |||
7e14032d2b | |||
bb0a0acbda | |||
9bbfb73622 | |||
d45d98d536 | |||
9e554ce527 | |||
6217f009fd | |||
46473126d2 | |||
b6ee6e9e22 | |||
1891f62c22 | |||
212d1cbfc2 | |||
73d93e476f | |||
80d82861ae | |||
8d034f53a4 | |||
6d3aa3a828 | |||
ed23aba0ac | |||
3847e5d6af | |||
f4465e2e9b | |||
fe2e87074a | |||
5b100d15d7 | |||
87cd36673e | |||
47b84f7316 | |||
a18da3e6cd | |||
6bb33fa18b | |||
59e6695a5d | |||
861cde7e61 | |||
e95d8d36aa | |||
04304ecf94 | |||
3989ea0780 | |||
e39585befc | |||
20fa14563c | |||
10910aa06d | |||
e6c2c90677 | |||
98712c7b71 | |||
2015d40186 | |||
a8aa34529e | |||
38cf0270b1 | |||
c8ca79f00b | |||
c02382b6e5 | |||
cb7c77d29e | |||
83e23c9c41 | |||
c6db90ae07 | |||
c2aa7263bd | |||
25be7ee14e | |||
332876495d | |||
6cbe50e3e7 | |||
599eaf85ce | |||
c03ca47e37 | |||
2246ce5142 | |||
79774921e4 | |||
ab453a0322 | |||
3725e400ce | |||
9859c7b25f | |||
056c1ef1fc | |||
41fbfb159a | |||
740a8a8d06 | |||
59ab9548c2 | |||
a1cf7f8d32 | |||
0d59983d1a | |||
488a57e2de | |||
dd9ad67e6b | |||
492e9d8df7 | |||
bc3b09dce4 | |||
5fd95ce374 | |||
77380a098e | |||
afc9c549d6 | |||
77f38bbf63 | |||
853eeb2e6b | |||
6ed6b4a679 | |||
99987f9373 | |||
b02239f3e3 | |||
bc436e9ec4 | |||
7e0874abb4 | |||
3d704702ba | |||
2735f80637 | |||
9275f7c2a9 | |||
229641aba0 | |||
ba143f2636 | |||
ffb34c3fd4 | |||
31c717eb40 | |||
7ae016bd3b | |||
501e0f63f5 | |||
a42398c457 | |||
d77e4ab10d | |||
8a8ea92140 | |||
adc46a80f9 | |||
3203f50a43 | |||
3dea5fd4f4 | |||
1024a2198a | |||
c8f0d5a3e4 | |||
3e55b3d7bc | |||
a93c4dfbbd | |||
aceb437c5f | |||
a137ccd8ba | |||
96bd4141fd | |||
e794762f72 | |||
9999b30d1a | |||
569e9681e5 | |||
9edc3eafa3 | |||
a1fcc35fd6 | |||
80d21ce80d | |||
08178b9354 | |||
60ce25c689 | |||
eaf34f3c3a | |||
ef0e907014 | |||
9fb0f56aa0 | |||
ae9ea8510c | |||
14409dec4f | |||
0cdea68567 | |||
542761e411 | |||
0dc8e070ff | |||
fe52cd8db1 | |||
d87a7e896b | |||
f7616ade1f | |||
f14379af68 | |||
a53df39e46 | |||
98187e2bd7 | |||
3ab7de99f3 | |||
1fef0691ed | |||
6b03efed42 | |||
eddd4abe76 | |||
e30dce8b21 | |||
6d12af3858 | |||
b9cbd0ecd1 | |||
3d7511ca75 | |||
fabf68b635 | |||
11326274e0 | |||
acd3940a7b | |||
8ba441da7f | |||
5d9d5e0746 | |||
7a31e88ed6 | |||
d9f35a855d | |||
9678d59bbe | |||
0be5564ce7 | |||
8a90051ab5 | |||
02c7a7f7c7 | |||
e7c8c1d6b6 | |||
449ad6d13c | |||
ae4ee0332c | |||
4a4c97aac4 | |||
4491da0350 | |||
32960afc1b | |||
46f624e3b9 | |||
9daae857de | |||
bac5b1551b | |||
f61f45fa23 | |||
fbc6e02ff6 | |||
56a17a9131 | |||
a148f7fd7c | |||
0dd0d01e8f | |||
bcd16d791c | |||
539e636939 | |||
7f1c4a1c4c | |||
6b254e0ad5 | |||
f36185a964 | |||
588487f860 | |||
f3ab2100f0 | |||
f96b40bbf8 | |||
9679de097f | |||
a51ad1383b | |||
1dd96fa714 | |||
8285805108 | |||
d91b3f8dd9 | |||
6734c928a2 | |||
58448f363b | |||
2e32b7e299 | |||
a651a1a69f | |||
c368696ddc | |||
94269c0640 | |||
5da6588ee6 | |||
ac9c6b4a1f | |||
aa8fa00811 | |||
9c4bd7a487 | |||
eb00294bbb | |||
04c60fd1ac | |||
80de8ada57 | |||
9cdb32d56a | |||
31a505f4a4 | |||
bfa6cd0e19 | |||
c51ecda6b4 | |||
471d44ae11 | |||
513bd1372b | |||
355cee0db9 | |||
38936173d1 | |||
eea56b4c71 | |||
802cc3a48f | |||
ba4720012d | |||
4f83b73732 | |||
68db13fc24 | |||
2d4dd580b4 | |||
d03e94ada8 | |||
91126a59c2 | |||
bd18aee43c | |||
4ead1c3de5 | |||
f3b2a6eba2 | |||
c4d9a27d2f | |||
fdcba2734d | |||
981ba7b28f | |||
822a1751a2 | |||
a4279d09a6 | |||
14d43ac05b | |||
5e6c92ab16 | |||
9ced745258 | |||
948f6ccd95 | |||
1c58727ca9 | |||
612bd9960c | |||
1474499886 | |||
cf99c68843 | |||
d2865b9f4f | |||
865c0c79db | |||
3462e7f50e | |||
37e412e710 | |||
5822992b44 | |||
eb7787fb7d | |||
f1371034f7 | |||
5d12dfa368 | |||
c4282011fa | |||
9ddc22fa94 | |||
517788e86a | |||
ed29ec528d | |||
481b26d09d | |||
da66ad6d41 | |||
1f75b305c3 | |||
0802d03d74 | |||
3970674003 | |||
b00a93dd6b | |||
19b33a8558 | |||
7918438747 | |||
31a085db73 | |||
72997eaa85 | |||
7bb91da1d0 | |||
e3e62c3903 | |||
631ed022ed | |||
590943ed95 | |||
e9c17c9a1d | |||
f8c8e42ae9 | |||
0b0560019a | |||
133d3fdda7 | |||
53e98dbe15 | |||
0eaa9187ea | |||
344f5bda69 | |||
33b080b3b8 | |||
1c85894472 | |||
ba4e5959b1 | |||
5534f9a248 | |||
eb206549ff | |||
0852f32b05 | |||
a1ea84b286 | |||
baba8790bc | |||
1da7f47af9 | |||
60d9b72fea | |||
7a7a8b7ed1 | |||
100565081c | |||
27f82434b6 | |||
353a9aa671 | |||
00da210365 | |||
bce6c86e60 | |||
bed6a1b1e2 | |||
497443f012 | |||
75a06afab0 | |||
121d9f4920 | |||
56371a7d80 | |||
2810787156 | |||
6b53cb59a5 | |||
64062cc879 | |||
7ca902e39a | |||
10ed2738f5 | |||
71392613b2 | |||
4eb7bed2ff | |||
ff21f5b357 | |||
98db248776 | |||
ed4872b94c | |||
8c5c6958cf | |||
f9c81f99f2 | |||
acfdb26135 | |||
37cf8e9d29 | |||
1c6670c9b0 | |||
88c72cd80a | |||
728ea16701 | |||
a3bc9f768a | |||
8d88bc19ed | |||
333ffa0e89 | |||
4ded810ba9 | |||
b2aa54f3f8 | |||
97836cc5eb | |||
b1df0dca97 | |||
4a6816575a | |||
31e2937b8d | |||
0f434004a8 | |||
ba75c45cee | |||
47492c3fa2 | |||
819917c4bf | |||
1ce0fd643c | |||
a7d02a79a9 | |||
645cbf9888 | |||
b2d39ab2d7 | |||
5843521cf1 | |||
4fbc45b40b | |||
2719da3685 | |||
f61bc809dd | |||
19f9593ac1 | |||
a479f529af | |||
76635ff31b | |||
e277cae799 | |||
05baf6b8ac | |||
758441d65d | |||
631a008fa0 | |||
71391914ae | |||
54e79936e5 | |||
a833822eae | |||
cfa8d8d180 | |||
b692756260 | |||
dbc62ad63a | |||
2ac97dea35 | |||
9451814299 | |||
5e01283018 | |||
f7512c3cc0 | |||
f4997375e9 | |||
fbad54795e | |||
2ca85d05f0 | |||
67e89e79be | |||
e4676668bb | |||
3604995c2f | |||
8b731f3ba4 | |||
83f702fbab | |||
fbebf1c7d3 | |||
be14947668 | |||
0fcf770043 | |||
51ec3ede1f | |||
4e2302936f | |||
a6c6a42669 | |||
c486bc64c4 | |||
3709ea1a95 | |||
be7fa79327 | |||
c1660f8ca2 | |||
5e41eaf3dd | |||
898e761988 | |||
846d52ebe5 | |||
77ac6a7a26 | |||
93c2dab634 | |||
f23ba0c513 | |||
824cfd4871 | |||
6a733bbb13 | |||
297d920fdc | |||
c741a73893 | |||
540e1f562f | |||
bfcd16ea28 | |||
3a8703de87 | |||
247ca71bf9 | |||
88d39ab47a | |||
a5af45fb31 | |||
dc04cb54ab | |||
c9fa82f073 | |||
c418cbf4ef | |||
3450c6b9a3 | |||
1ada33a4f0 | |||
a669852694 | |||
a5b6ea6c4c | |||
fe217ef5df | |||
e0a25dbf48 | |||
86191aff7f | |||
6bed39e4fa | |||
2a7aa432a9 | |||
4e19e41460 | |||
061f5d5099 | |||
796bdebd90 | |||
010102da25 | |||
d8f2aeb004 | |||
5173338949 | |||
a8b00b026e | |||
d4db0bdfe5 | |||
b26cd901ca | |||
1e2fc783e5 | |||
8667333416 | |||
5088d7dd86 | |||
e78f26e9c0 | |||
be10227829 | |||
ef47c172c5 | |||
053faa1661 | |||
6d63779c70 | |||
62ad1a483c | |||
f4f760a231 | |||
0eaef1ac3b | |||
27245cca1a | |||
afcc11af57 | |||
9fc41e4245 | |||
a0e0910117 | |||
8a7d7a41a4 | |||
45d5f4a760 | |||
101b795c0a | |||
8311bd3fd9 | |||
ec1926f7a6 | |||
e1c92956f8 | |||
9233d4f6dc | |||
f2f5661625 | |||
4338cf57e6 | |||
a0dce77a2f | |||
ca93882870 | |||
22fbb4262c | |||
2845fd07a7 | |||
c02f40beb6 | |||
79a7b444a2 | |||
9c11bbc7a1 | |||
e1cb57563a | |||
1057d765f7 | |||
30db1a8a63 | |||
c7b49b28c2 | |||
40ea7cfe15 | |||
b3b2ae267a | |||
88176f4d2b | |||
6917ac48a3 | |||
c326d65ad3 | |||
e1a2f0c0f4 | |||
6953bc6105 | |||
209555d36d | |||
e65958f33e | |||
02fea8938a | |||
f5277e4931 | |||
d78ed32df5 | |||
8447395482 | |||
915a7b6e15 | |||
b70c39789e | |||
865cb4857b | |||
774abd66fa | |||
e52d86e6f9 | |||
3c0b5b0b43 | |||
46068573c5 | |||
06c29b7810 | |||
631452567d | |||
6c34f00cfe | |||
208c7f18b2 | |||
5e393ed3c4 | |||
8b16abd370 | |||
94c232d78e | |||
4b41c52522 | |||
6bfe533a20 | |||
f0b8aad4b1 | |||
796cf36a7f | |||
7706d66754 | |||
d992536914 | |||
286b76672c | |||
f0d1b5a1e4 | |||
71ad8930d8 | |||
0f6cbb0c5c | |||
78584b3194 | |||
c0eb4d652b | |||
edbb28038f | |||
3b7e9b4eba | |||
6d0d07abfe | |||
e9f90b4990 | |||
d25b65c124 | |||
5864864123 | |||
2f244ae37e | |||
f83317f7c8 | |||
973b4b9f70 | |||
9389ceaf4f | |||
928dc30810 | |||
c9d6d10995 | |||
9323e1cf59 | |||
93a456ca82 | |||
f6693d5587 | |||
fd09a0ce54 | |||
50d3a2600e | |||
7e1b05933f | |||
03c4fdc607 | |||
0485cf51ff | |||
ba9201831b | |||
f660036a25 | |||
f09cbfddbc | |||
a12f1dcb13 | |||
d2bb1ddc29 | |||
528d81106e | |||
f0bed24742 | |||
5b54d8135e | |||
31559051f6 | |||
e6dbc9bfdf | |||
d1ee9d83b5 | |||
ffa6371e3d | |||
ee6e241144 | |||
bdf1023b16 | |||
9a8f248a75 | |||
6845cda146 | |||
4488b2b7a5 | |||
7dd8cb5d8d | |||
ebf631a15f | |||
3770b75a78 | |||
5d81b61325 | |||
a8e5171b40 | |||
a3e0abb6ce | |||
c51f20eb99 | |||
be897c4df2 | |||
11b948fb69 | |||
070660848b | |||
61af0ec9c6 | |||
897f115363 | |||
b8fcf0355c | |||
5bdff87e3f | |||
31991a3567 | |||
25c369d422 | |||
8d396b1518 | |||
ba327b746a | |||
7d11f912c9 | |||
919cdfb5a9 | |||
da9dd6f775 | |||
8b841f026e | |||
5342b39640 | |||
fc08add504 | |||
20379ac61e | |||
af40aa59ab | |||
f9afc5597a | |||
40178e4661 | |||
ad56abd6f5 | |||
9073a09d84 | |||
2a4e6fce3f | |||
0a3a407217 | |||
9ca9cf80df | |||
6c881a5da7 | |||
5322acd58c | |||
ce489e53c6 | |||
0c95e509dc | |||
46a006ed54 | |||
0cc9378d05 | |||
f3edb2ee68 | |||
a539f23194 | |||
6b6dec79c5 | |||
d7f5c042bf | |||
2fe9812b26 | |||
1c15c3c7a3 | |||
1ee5857139 | |||
2f9c2b0d65 | |||
6e5161f43b | |||
d492d74a64 | |||
26506731c5 | |||
b0c03d4f47 | |||
3bc8348c32 | |||
a034fbba83 | |||
73b5261c49 | |||
cee0cbebc2 | |||
9723147429 | |||
dca385ae87 | |||
71f792944c | |||
6041c4acd2 | |||
0c7529705e | |||
63f1ea1cec | |||
4bbaa75f41 | |||
5fe9314b74 | |||
bfd26493ab | |||
5d74d5d03e | |||
3142e097a5 | |||
b25d8d8201 | |||
7e68cd016a | |||
9e4fc9eb73 | |||
fb0d13a171 | |||
f097b36c2e | |||
57ce3cf80b | |||
c1da62391f | |||
d8882ce979 | |||
9c1871494e | |||
ac26c9114a | |||
fb0a57003c | |||
cda22233a6 | |||
add307577d | |||
4af46ac2b9 | |||
8d39752bda | |||
e3ff9c013e | |||
635870ba4b | |||
a827afb05b | |||
0195e13bdc | |||
76d8b688fd | |||
b4857e2c79 | |||
ac2ae90e8a | |||
0b5cb76b5d | |||
a5bc979c24 | |||
6eed9606ae | |||
29679ff94c | |||
65a1f8b746 | |||
48182d35bd | |||
b526ed47be | |||
2225dec2a9 | |||
011458d642 | |||
e32fff3f61 | |||
0b42e3d0f3 | |||
2b746d1353 | |||
6fed6f9f7d | |||
480945073a | |||
ef6df94838 | |||
fb05848426 | |||
e5be6b96fb | |||
2d706a245a | |||
1abc4f491b | |||
b21a45b43e | |||
585f8450e1 | |||
d3401db5fe | |||
45dc6447bf | |||
409c270ba2 | |||
aed0234d47 | |||
07ebbe56e6 | |||
47b485819f | |||
fd32f7f435 | |||
c4b07b1a7b | |||
95bbeb103e | |||
bfb5570b7a | |||
1e19cf7ccc | |||
0d8999d64f | |||
91fde777cf | |||
061ab12b10 | |||
c516e87180 | |||
de6bfdca0a | |||
788f70d5f3 | |||
b0a35789f6 | |||
eb7fbf011f | |||
50bb6e7204 | |||
15610bb296 | |||
ae0ffdc4d5 | |||
033a6929c3 | |||
7c8292a88d | |||
ab5dad7d91 | |||
0744d215c6 | |||
2622eb4663 | |||
74b3dc2831 | |||
149ddfa8f8 | |||
3830870a83 | |||
b94be080f6 | |||
83382d8dcf | |||
f815228677 | |||
d7d8d23de7 | |||
5834c6ed54 | |||
b0512b3ba7 | |||
d3a7a6ef55 | |||
99fad5bc83 | |||
a54171e1cd | |||
84629f6e63 | |||
b18d597bdc | |||
9125dc4cce | |||
b0e3ea8765 | |||
7c457546f1 | |||
83bef1a840 | |||
b4d89d5666 | |||
3ba8a77d9a | |||
82c31dc47a | |||
7fce694577 | |||
e352d9750d | |||
3d9eac8e6d | |||
6c85b33539 | |||
d979ada4fe | |||
faeeae17d1 | |||
82d1a2b4f9 | |||
cac3496145 | |||
53bfa077ae | |||
0b9366fa28 | |||
c95b709f39 | |||
5745da5466 | |||
ef853e34d6 | |||
7177913d9b | |||
86b6ddb625 | |||
53b9a46feb | |||
d46c1f8687 | |||
c92477b457 | |||
059244bb32 | |||
f10c0d2558 | |||
f5ae89500f | |||
2e3a24d32e | |||
f955d81c5e | |||
4f1fa3bc32 | |||
8305d907e3 | |||
ab73d61178 | |||
8f88d1b7c4 | |||
c5cdbc48a9 | |||
fe00f31147 | |||
79ddb43ac3 | |||
89f95f6459 | |||
87c13b6f26 | |||
d16ea653fe | |||
51dc7fceb0 | |||
bc1c6f7b9a | |||
3fdf77d29b | |||
0b97502029 | |||
cba2bf5cb8 | |||
d8b37328a1 | |||
bb9cf83744 | |||
56fc6ae47c | |||
0cf17cf3db | |||
1bd3297055 | |||
6a10662bc4 | |||
2d84ad8963 | |||
1ec69cbc0d | |||
0057744e57 | |||
45892b4347 | |||
3d41e8882a | |||
436b8216ec | |||
03ba2a680e | |||
2821962d12 | |||
43d38a2e63 | |||
ea28d217e0 | |||
89fe6d57c9 | |||
1d0e1143bf | |||
1a99353559 | |||
ad97d04e37 | |||
25c3abe873 | |||
8eeea50ede | |||
0ded11c6a2 | |||
b6c542212d | |||
182bde4884 | |||
eb84f677cf | |||
3ecb637e70 | |||
bfc826b898 | |||
efc6d4c15a | |||
a96da35f11 | |||
2bff3798af | |||
0fb50a3273 | |||
1c17eee125 | |||
14a43a9cd2 | |||
7bbc7366f2 | |||
879bedd781 | |||
8b79bfab4f | |||
f022e09938 | |||
a63b6a0e3d | |||
dd1facec06 | |||
a46b5716be | |||
e96b7bfd62 | |||
a60c1c1365 | |||
4c39fcd614 | |||
e6b341f2a0 | |||
bdf9e76a6b | |||
e0fc395fbe | |||
107c03653d | |||
a5058cf951 | |||
ed2726c9d2 | |||
6b31ff7e79 | |||
86d3925bf4 | |||
8c2cde4c13 | |||
2d6e34ee6d | |||
adb5577b01 | |||
84ef3f223d | |||
fa50008f3d | |||
6a5537f90f | |||
e0d33a9683 | |||
4092c9a473 | |||
fcaac3d515 | |||
e86d1aad02 | |||
2c94b4c332 | |||
2b6933f6e2 | |||
2e2a7f073e | |||
515c7852ba | |||
5577277944 | |||
ed9e4ff168 | |||
d10915c7a8 | |||
40763fc15d | |||
88d3271c40 | |||
21940c922d | |||
93adc8587d | |||
1907f8d1d1 | |||
ca8848827e | |||
3a7473ba91 | |||
a99da27ff6 | |||
c476649f3e | |||
062473d6f4 | |||
d0ed43a8e5 | |||
701098d19d | |||
c33a0ab439 | |||
b8af848d3a | |||
3dd7fe5d4a | |||
81ab199308 | |||
92938d2c35 | |||
c914632663 | |||
c95104fada | |||
2209fe30e2 | |||
979e0ddc88 | |||
9fab714674 | |||
2eb6463ab0 | |||
5e4d6fbd3f | |||
30df5f3558 | |||
252dd7e09f | |||
2915690d22 | |||
1993596232 | |||
8946e8997f | |||
dfeb156da9 | |||
c10c35e38e | |||
67bfdde113 | |||
c62178a7fe | |||
c12a4323e7 | |||
fd1c4abad7 | |||
bd4fe5a1a7 | |||
190f5ebfc4 | |||
79493df32e | |||
71d523437e | |||
268f503875 | |||
5ac47b823f | |||
ec572da822 | |||
37f96b8cf2 | |||
545db60b98 | |||
f65fdcdbc1 | |||
579acabe5e | |||
f2a9ff8551 | |||
2e40e07563 | |||
cb3af837c6 | |||
3cce89ea3f | |||
5f2dfb24ca | |||
4bc02a7389 | |||
eeeca8afd0 | |||
4f607df5fc | |||
e06b3e2052 | |||
b14b18e4be | |||
fb616b4b53 | |||
a1c5bc00bc | |||
0921632f87 | |||
38ad465233 | |||
881de01073 | |||
2d973e0b90 | |||
e9b43b9b2a | |||
b9193989b0 | |||
be6d9791f5 | |||
baac1b1d80 | |||
40e2d410dd | |||
11617eea99 | |||
5748c4d0ec | |||
2e5b903eae | |||
9405b17e14 | |||
7d1f0e2a69 | |||
c245c24752 | |||
5b0410a207 | |||
62e4c42aa6 | |||
fe1b14ff57 | |||
c074088f2f | |||
0391280c13 | |||
4f98b9e41b | |||
a8de9ac472 | |||
ec7f3fa057 | |||
5cfefd8b15 | |||
7e6b53311d | |||
16bc68f2f9 | |||
974d6b48b2 | |||
db2b1e2dc7 | |||
98656b5d2f | |||
3c7570d814 | |||
fc3e30a826 | |||
2f0476b43c | |||
e310c7d744 | |||
8a649b89c8 | |||
95f52987ef | |||
82b8c66d51 | |||
83fb1843ee | |||
58b10069ab | |||
9cda739672 | |||
276bba050b | |||
147e49b362 | |||
bc338c1f4a | |||
e8fbb18a71 | |||
682c349831 | |||
14b311f6ab | |||
8a40f355c8 | |||
ae2f90c5c2 | |||
7aff773e2c | |||
0cdfa6e7f6 | |||
fc637eef6d | |||
b4c3141170 | |||
41257f7af5 | |||
b204f3ec90 | |||
b4926b3535 | |||
77d63e9848 | |||
94dcd58c2e | |||
689ce16f1b | |||
edc64b8336 | |||
03db5bfd8d | |||
9ad340ab02 | |||
962e26040d | |||
b07884c1da | |||
bad0fb62ed | |||
28e522ce97 | |||
c206cdfa4c | |||
c31ec077f5 | |||
afc6a60746 | |||
0a495b67e6 | |||
37ea7073d5 | |||
feaeef5a70 | |||
5586670d38 | |||
65a9139ffe | |||
3d76f078cd | |||
a1de1b11bc | |||
b5a3e3a4f0 | |||
d7b0ad4916 | |||
2a80a6b217 | |||
9df72f54d5 | |||
ef75ca36c9 | |||
84c0b698f5 | |||
3d9a4ef1e6 | |||
cf51fdceef | |||
85a52ab01f | |||
f2792c0b40 | |||
97109087a4 | |||
953f07f21f | |||
03f1035690 | |||
a561c60f7e | |||
7963b328f9 | |||
3b7e216409 | |||
9ae43a6f75 | |||
6b86de1fb9 | |||
4e6d4ac437 | |||
3b197651cc | |||
c675f1c20c | |||
e87955d59a | |||
c718d8d803 | |||
454a68d1b7 | |||
45f6f74cbe | |||
cb7412a457 | |||
a9fc82365c | |||
edc0fed9e2 | |||
1c718963ea | |||
cd40ccdb9d | |||
80e1dc2446 | |||
d03c4cc4b9 | |||
7bd434e755 | |||
640bcb90c6 | |||
08e86a1378 | |||
fefcc3937a | |||
25210dfa52 | |||
56fbb7b9cf | |||
c55d33b956 | |||
0c5bce101e | |||
0a50e2a95c | |||
5ad940924b | |||
6eb49930bf | |||
3a0d5fb190 | |||
8c2eee2e25 | |||
2e19c5f08a | |||
548b53437f | |||
e1ca9a8029 | |||
389ef2aea9 | |||
357691bad5 | |||
beadb56b05 | |||
745fb5ea29 | |||
58434cac3b | |||
c34dff17ff | |||
73f00ca195 | |||
40503b4212 | |||
4ada388828 | |||
e2d261259d | |||
677e393f47 | |||
e5dae8f5a7 | |||
650de119a4 | |||
6d7975afeb | |||
811e3f8cc8 | |||
4f3be34db1 | |||
b160fd2320 | |||
002bf08b97 | |||
a6bab968f5 | |||
408b336057 | |||
7e5716185e | |||
6d47bd6477 | |||
989c8b1857 | |||
06e9e0afab | |||
d75523c111 | |||
dacec803c6 | |||
0ae4416242 | |||
079d7eb6ca | |||
b764b4d0e5 | |||
2c2d61d908 | |||
6a323b9371 | |||
d76ff16162 | |||
952f3a586a | |||
3ecb9702ef | |||
563936ea08 | |||
13cd2704ae | |||
ae83d9dca1 | |||
66a059ecdf | |||
53936a4f76 | |||
488a095fdf | |||
1878de9f6b | |||
2a2f3441ef | |||
53c939a97f | |||
8d7ed32fc2 | |||
a1fa5dc3cb | |||
4b9a84ccee | |||
650957b6d1 | |||
6e21d041fe | |||
e2b70fd795 | |||
2d49bcc437 | |||
8b3dce3256 | |||
8cf6a1e72c | |||
a3ce7197ac | |||
5da1e55f8e | |||
661fd4efa8 | |||
047e6e11bf | |||
db8bc1af2d | |||
1386e4f91c | |||
11e2717809 | |||
57bc0a2b95 | |||
8efb30c4ee | |||
969feefcc5 | |||
db1527ab9b | |||
e88a60fa50 | |||
7ab3e38da7 | |||
7b0b836809 | |||
c8e7cfcd7b | |||
c516c89c97 | |||
c2937d7857 | |||
fe644cfa82 | |||
e84e5388a5 | |||
5e11d0ea13 | |||
a3ecb6e0e9 | |||
1d30f13fd8 | |||
b9ae28483c | |||
6a6d316e09 | |||
22d2ee6bbd | |||
68e55613fc | |||
1d44d3a109 | |||
11a641cc0d | |||
7570fbf7a4 | |||
67f7e28867 | |||
9b2d30b4d5 | |||
399815525f | |||
191cfa08d5 | |||
fcf1fa8aff | |||
73302cb060 | |||
70a8533f5e | |||
fe724db12d | |||
096a8ec6ba | |||
cc5f9c9aa7 | |||
3e14b41600 | |||
ccc2bd8667 | |||
45f86b17f1 | |||
90aebecc5b | |||
b0170ef671 | |||
d418b4e624 | |||
47505547af | |||
de2e73c9d4 | |||
ab1a43163b | |||
2556dd320f | |||
2120381c0e | |||
dc06900f7f | |||
7571dd5042 | |||
d6caa872b8 | |||
2e9829ddd1 | |||
9621ea90f7 | |||
f58da1254b | |||
a6ba7f8feb | |||
9c89f12275 | |||
41181f7260 | |||
7251862ecf | |||
c0512d5b5f | |||
b9731dff21 | |||
3981abc5ca | |||
6aef437f58 | |||
9b7752896a | |||
d074027610 | |||
b137148186 | |||
e1f6260034 | |||
b24cbaa904 | |||
cc0b110d61 | |||
82a1e7d253 | |||
87b47689eb | |||
c3346f9192 | |||
3b0cf02574 | |||
4404889019 | |||
4e642d97fc | |||
44bd25646d | |||
09b04037a0 | |||
3c50e1e4d8 | |||
179ba9a9e6 | |||
9ce2b1983a | |||
37dde278cb | |||
1cc57e7d1d | |||
60a5cdb154 | |||
f290cbc148 | |||
2e2e9b1332 | |||
7915e3815b | |||
beb34deed8 | |||
a263d8a364 | |||
1eccf4c899 | |||
d8d19d839a | |||
17e573d67f | |||
59de83b45d | |||
712bd6e8f3 | |||
75b21d070a | |||
e91c9e7bf4 | |||
2562272775 | |||
819621e307 | |||
4b9229311c | |||
4c4c1de190 | |||
6b6b7feff2 | |||
9e3ce26ba0 | |||
eac19a7c83 | |||
ee1486274d | |||
8692e2afda | |||
f995268444 | |||
bd2e974718 | |||
d1c64c7509 | |||
30a19cfe8a | |||
cc3097b09a | |||
c00681b52d | |||
61931c179f | |||
c7190cb94a | |||
a1bd27dfde | |||
6ac3a3de57 | |||
e198ed7a9c | |||
4b89464349 | |||
dba599c127 | |||
586f9076f0 | |||
add39cfc5f | |||
e3ad148c15 | |||
acffacd67d | |||
54a16f4d2f | |||
35cb506d6e | |||
7675a1ee58 | |||
863f5e28b3 | |||
1a6f6096e4 | |||
b57982b6cb | |||
4132356141 | |||
e560e95310 | |||
65f4ff6a30 | |||
ab38f33530 | |||
1f04ee8252 | |||
739bd6f696 | |||
066145ab31 | |||
54d0f764d4 | |||
1398689ebf | |||
647625628d | |||
e17df69b80 | |||
f001d18eea | |||
f49980350a | |||
d0a90ecea4 | |||
4506b46ba0 | |||
a8c36d7366 | |||
781eaec683 | |||
bdee8f318a | |||
82dac4d208 | |||
386e1f3b46 | |||
a3cbbf3ea9 | |||
e647debcfb | |||
fba9bd2b76 | |||
56217e0176 | |||
77c5801c4c | |||
7db879cca9 | |||
8d0cb2e875 | |||
dc7b386295 | |||
03c8c6385c | |||
841de2f752 | |||
9de6e229d9 | |||
8dfe471ef2 | |||
da05f315be | |||
d014a7ab25 | |||
d0118c63c0 | |||
9ddfad99ea | |||
82d74fcb2f | |||
0f4f029a76 | |||
2c581e9998 | |||
f2028c506a | |||
200db77140 | |||
007604cc21 | |||
89486e9172 | |||
a60ca96fd1 | |||
0ade2c869d | |||
9986382850 | |||
89b9165c25 | |||
5d290165a2 | |||
d267171cc7 | |||
cebe325e81 | |||
4e6178881b | |||
6bca8194cb | |||
a4885f332d | |||
cf97fb2051 | |||
20a8853854 | |||
dd487a5055 | |||
72ca07f571 | |||
c7305889c3 | |||
bc24497760 | |||
200e65c730 | |||
b32d8ef1e7 | |||
8cfc613a3d | |||
5fbc2cbac7 | |||
9d7a32aa1f | |||
bcc9ef82d1 | |||
d6b28191e8 | |||
acd8a9ea69 | |||
d4b8a8ff9e | |||
a698f7bdf5 | |||
16f07ff0c3 | |||
ed4526751e | |||
e241518f8d | |||
a6677edbf5 | |||
5748e163f8 | |||
85fa6b60e2 | |||
f0bb941c47 | |||
b7df1e8596 | |||
ff8eda3682 | |||
8c4bd91c78 | |||
07c868edcd | |||
69061869a7 | |||
98b2ac9bdc | |||
ef2bbff4e5 | |||
7bb8e56072 | |||
df0926f6fd | |||
75572279a9 | |||
328c6a0f7c | |||
ecd5062975 | |||
c01ae5610d | |||
564e7f31c3 | |||
efa61952b3 | |||
ae27a26ebe | |||
d81076f720 | |||
528f16c5e1 | |||
13ac8bfa90 | |||
935c58b17b | |||
31e133bf06 | |||
eb7fb6694c | |||
a298577da1 | |||
8cd6d43ec4 | |||
b8fd143cc1 | |||
045ae058a3 | |||
52c9816db2 | |||
32440580f6 | |||
906d986f4b | |||
0198651ca0 | |||
d911c40897 | |||
ca8a117335 | |||
f75e2f0ada | |||
ea12b62235 | |||
0af4af7e50 | |||
f017491f44 | |||
ed433d3312 | |||
9ba2e83857 | |||
af0ec74704 | |||
251402e844 | |||
1a5318ebe0 | |||
15aac3f436 | |||
5f373632e6 | |||
0d518bf8df | |||
16b735c3a4 | |||
1239f094fd | |||
6986fa51eb | |||
f4bc88bf73 | |||
ad915536a3 | |||
f48b31664e | |||
d6c0eb1998 | |||
d3dcfba463 | |||
3619dcd777 | |||
86c002e318 | |||
42a807ce9c | |||
9bfff9539e | |||
edf4d919fe | |||
b0fb3d8c61 | |||
5143090142 | |||
bc1555ca5b | |||
146a392f1a | |||
e2fc205a35 | |||
d4bdb216d2 | |||
bffc1d6a1f | |||
df0d890c11 | |||
dceee4dede | |||
dedbbf12bb | |||
bdb53d07f5 | |||
547991df72 | |||
fd17557a96 | |||
a9e928a799 | |||
84b3e086e6 | |||
5e3c794aec | |||
98acbb2b2b | |||
318f0753b0 | |||
8908adbdee | |||
fad7a26550 | |||
38005fc0ef | |||
e3d3181ad6 | |||
83d069e4d9 | |||
f2db5a8229 | |||
6ebb777256 | |||
db50c531d9 | |||
218f7af2e3 | |||
a19d2956c1 | |||
7a6b5b965d | |||
8a871aaddd | |||
bec0a0df10 | |||
1068a2dfbe | |||
b62be5d584 | |||
9686019693 | |||
32a066b4d4 | |||
d5a415e01e | |||
33f83b8486 | |||
adedf8d34f | |||
9243071f03 | |||
36050850d4 | |||
c6d5cc555a | |||
b271aa2aaa | |||
d24961b3b9 | |||
e52543efe7 | |||
0b0e27ad3b | |||
9f460f6c99 | |||
c4529bb9a3 | |||
5a069d2ffc | |||
4fc78e455a | |||
75e2198315 | |||
0d4bb4ed2d | |||
577738ad0a | |||
a8dfdb03fb | |||
aebd470d49 | |||
ce3dfd9678 | |||
b82801b145 | |||
a6ab35f1fb | |||
a265cea4fb | |||
166760651e | |||
41a9191223 | |||
1465e7760e | |||
1a043f1dc0 | |||
70c5b00c90 | |||
bb5177dc79 | |||
f60a9a632b | |||
024c47132b | |||
73ce9cb4cc | |||
f45d439094 | |||
2d5749a78c | |||
f078a10028 | |||
701f88e532 | |||
1524a1997d | |||
b16f812f91 | |||
cde307d644 | |||
c47f6d093c | |||
f5336938c9 | |||
4985548edf | |||
8bc4841e84 | |||
634f9833a1 | |||
80052e62ee | |||
0672b6a157 | |||
1e71bfa151 | |||
d4c2c8197a | |||
c9baed2df9 | |||
1e2065c84a | |||
537d683dfb | |||
e6f1b9f8c8 | |||
5815d2bfce | |||
7692e93306 | |||
8768b83251 | |||
35d18810fc | |||
ccd40a1834 | |||
5c1f0c3541 | |||
e237e52ae4 | |||
effec90528 | |||
de4a2247c0 | |||
b20b7cbc98 | |||
3c347b9b77 | |||
794c4066d8 | |||
8c8e3072a7 | |||
228708eec4 | |||
dcafaedaa8 | |||
a85297f2c8 | |||
91f7450cbd | |||
e7b074991d | |||
5f83ce2a28 | |||
44af896dee | |||
9eaa9a98ee | |||
629880cd58 | |||
42266ed14f | |||
9dd7a197e4 | |||
6f39da20a9 | |||
1ebb6f9257 | |||
e30e982ef0 | |||
42a80c6185 | |||
0d495f4d65 | |||
71f5e66bd1 | |||
a6f71b68f3 | |||
a527f343cd | |||
f8e1c454d9 | |||
da6e55f09f | |||
d277e2788a | |||
53ba747b78 | |||
b9862acd1d | |||
d1c19382a1 | |||
4141983ccd | |||
2b8b5001e0 | |||
532126561e | |||
3c026c4eef | |||
ae6c15158f | |||
6aa57247f9 | |||
50862ac945 | |||
01ce6faa20 | |||
6e571aef95 | |||
d6091c83e2 | |||
5ca55fc13e | |||
2b60da02e8 | |||
f02297152c | |||
af7c0bbc72 | |||
40727d5a6c | |||
9bdd73dbc6 | |||
3e1ed09f12 | |||
3682c625d7 | |||
70cd52ac95 | |||
3264da4b2f | |||
06c1648f55 | |||
94c3e5d41d | |||
7ae20d8c3b | |||
0ff4411abf | |||
3d68b7c9e5 | |||
f8b1cae0c9 | |||
5bee0fc453 | |||
7162765824 | |||
99aa6be887 | |||
afaaff298f | |||
68cf9af6a3 | |||
8d5752d6b5 | |||
98dbcc4c69 | |||
687d8fd120 | |||
114ace23f7 | |||
3fbc221db0 | |||
f2e6e137a6 | |||
bb232f1b3e | |||
9dc153bc22 | |||
b9bbdf5978 | |||
e0db0e394d | |||
3e9001721e | |||
bbf3b0f86f | |||
7f3eb9f11b | |||
c783c51915 | |||
0816d222c6 | |||
af16c70143 | |||
748b6f6e2e | |||
3bd600ed52 | |||
78e6ad0f59 | |||
2d71dc68f1 | |||
7dc2a00d47 | |||
7ece78a05b | |||
ff2bace1bf | |||
e63ce01bdc | |||
4439ce71d0 | |||
27ec094775 | |||
1bed53e07b | |||
8ae06c0c4f | |||
372db7865b | |||
cfeffc551e |
10
.editorconfig
Normal file
10
.editorconfig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[*]
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.{c,cpp,h,hpp}]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
open_collective: obs-websocket
|
||||||
|
github: Palakis
|
||||||
|
custom: https://www.paypal.me/stephanelepin
|
20
.github/ISSUE_TEMPLATE.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
##### Issue type
|
||||||
|
<!--- Uncomment one of the two options below. -->
|
||||||
|
|
||||||
|
<!--- - Bug report -->
|
||||||
|
<!--- - Feature request -->
|
||||||
|
|
||||||
|
##### Description
|
||||||
|
<!--- Describe the bug encountered or feature requested. -->
|
||||||
|
|
||||||
|
##### Steps to reproduce and other useful info
|
||||||
|
<!--- If it's a bug, please describe the steps to reproduce it and PLEASE include an OBS log file. Otherwise, remove this section. -->
|
||||||
|
|
||||||
|
##### Technical information
|
||||||
|
- **Operating System** :
|
||||||
|
- **OBS Studio version** :
|
||||||
|
- **obs-websocket version** :
|
||||||
|
|
||||||
|
##### Development Environment
|
||||||
|
<!--- If you're trying to compile obs-websocket, please describe your compiler type and version (e.g: GCC 4.7, VC2013, ...), and the CMake settings used. -->
|
||||||
|
<!--- Remove this section if it does not apply. -->
|
77
.github/actions/build-plugin/action.yml
vendored
Normal file
77
.github/actions/build-plugin/action.yml
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
name: 'Setup and build plugin'
|
||||||
|
description: 'Builds the plugin for specified architecture and build config.'
|
||||||
|
inputs:
|
||||||
|
target:
|
||||||
|
description: 'Build target for dependencies'
|
||||||
|
required: true
|
||||||
|
config:
|
||||||
|
description: 'Build configuration'
|
||||||
|
required: false
|
||||||
|
default: 'Release'
|
||||||
|
codesign:
|
||||||
|
description: 'Enable codesigning (macOS only)'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
codesignIdent:
|
||||||
|
description: 'Developer ID for application codesigning (macOS only)'
|
||||||
|
required: false
|
||||||
|
default: '-'
|
||||||
|
visualStudio:
|
||||||
|
description: 'Visual Studio version (Windows only)'
|
||||||
|
required: false
|
||||||
|
default: 'Visual Studio 16 2019'
|
||||||
|
workingDirectory:
|
||||||
|
description: 'Working directory for packaging'
|
||||||
|
required: false
|
||||||
|
default: ${{ github.workspace }}
|
||||||
|
runs:
|
||||||
|
using: 'composite'
|
||||||
|
steps:
|
||||||
|
- name: Run macOS Build
|
||||||
|
if: ${{ runner.os == 'macOS' }}
|
||||||
|
shell: zsh {0}
|
||||||
|
env:
|
||||||
|
CODESIGN_IDENT: ${{ inputs.codesignIdent }}
|
||||||
|
run: |
|
||||||
|
build_args=(
|
||||||
|
-c ${{ inputs.config }}
|
||||||
|
-t macos-${{ inputs.target }}
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ '${{ inputs.codesign }}' == 'true' ]] build_args+=(-s)
|
||||||
|
if (( ${+CI} && ${+RUNNER_DEBUG} )) build_args+=(--debug)
|
||||||
|
|
||||||
|
${{ inputs.workingDirectory }}/.github/scripts/build-macos.zsh ${build_args}
|
||||||
|
|
||||||
|
- name: Run Linux Build
|
||||||
|
if: ${{ runner.os == 'Linux' }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
build_args=(
|
||||||
|
-c ${{ inputs.config }}
|
||||||
|
-t linux-${{ inputs.target }}
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ -n "${CI}" && -n "${RUNNER_DEBUG}" ]]; then
|
||||||
|
build_args+=(--debug)
|
||||||
|
fi
|
||||||
|
|
||||||
|
${{ inputs.workingDirectory }}/.github/scripts/build-linux.sh "${build_args[@]}"
|
||||||
|
|
||||||
|
- name: Run Windows Build
|
||||||
|
if: ${{ runner.os == 'Windows' }}
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$BuildArgs = @{
|
||||||
|
Target = '${{ inputs.target }}'
|
||||||
|
Configuration = '${{ inputs.config }}'
|
||||||
|
CMakeGenerator = '${{ inputs.visualStudio }}'
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( Test-Path env:CI ) -and ( Test-Path env:RUNNER_DEBUG ) ) {
|
||||||
|
$BuildArgs += @{
|
||||||
|
Debug = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${{ inputs.workingDirectory }}/.github/scripts/Build-Windows.ps1 @BuildArgs
|
99
.github/actions/package-plugin/action.yml
vendored
Normal file
99
.github/actions/package-plugin/action.yml
vendored
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
name: 'Package plugin'
|
||||||
|
description: 'Packages the plugin for specified architecture and build config.'
|
||||||
|
inputs:
|
||||||
|
target:
|
||||||
|
description: 'Build target for dependencies'
|
||||||
|
required: true
|
||||||
|
config:
|
||||||
|
description: 'Build configuration'
|
||||||
|
required: false
|
||||||
|
default: 'Release'
|
||||||
|
codesign:
|
||||||
|
description: 'Enable codesigning (macOS only)'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
notarize:
|
||||||
|
description: 'Enable notarization (macOS only)'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
codesignIdent:
|
||||||
|
description: 'Developer ID for application codesigning (macOS only)'
|
||||||
|
required: false
|
||||||
|
default: '-'
|
||||||
|
installerIdent:
|
||||||
|
description: 'Developer ID for installer package codesigning (macOS only)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
codesignUser:
|
||||||
|
description: 'Apple ID username for notarization (macOS only)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
codesignPass:
|
||||||
|
description: 'Apple ID password for notarization (macOS only)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
createInstaller:
|
||||||
|
description: 'Create InnoSetup installer (Windows only)'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
workingDirectory:
|
||||||
|
description: 'Working directory for packaging'
|
||||||
|
required: false
|
||||||
|
default: ${{ github.workspace }}
|
||||||
|
runs:
|
||||||
|
using: 'composite'
|
||||||
|
steps:
|
||||||
|
- name: Run macOS packaging
|
||||||
|
if: ${{ runner.os == 'macOS' }}
|
||||||
|
shell: zsh {0}
|
||||||
|
env:
|
||||||
|
CODESIGN_IDENT: ${{ inputs.codesignIdent }}
|
||||||
|
CODESIGN_IDENT_INSTALLER: ${{ inputs.installerIdent }}
|
||||||
|
CODESIGN_IDENT_USER: ${{ inputs.codesignUser }}
|
||||||
|
CODESIGN_IDENT_PASS: ${{ inputs.codesignPass }}
|
||||||
|
run: |
|
||||||
|
package_args=(
|
||||||
|
-c ${{ inputs.config }}
|
||||||
|
-t macos-${{ inputs.target }}
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ '${{ inputs.codesign }}' == 'true' ]] package_args+=(-s)
|
||||||
|
if [[ '${{ inputs.notarize }}' == 'true' ]] package_args+=(-n)
|
||||||
|
if (( ${+CI} && ${+RUNNER_DEBUG} )) build_args+=(--debug)
|
||||||
|
|
||||||
|
${{ inputs.workingDirectory }}/.github/scripts/package-macos.zsh ${package_args}
|
||||||
|
|
||||||
|
- name: Run Linux packaging
|
||||||
|
if: ${{ runner.os == 'Linux' }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
package_args=(
|
||||||
|
-c ${{ inputs.config }}
|
||||||
|
-t linux-${{ inputs.target }}
|
||||||
|
)
|
||||||
|
if [[ -n "${CI}" && -n "${RUNNER_DEBUG}" ]]; then
|
||||||
|
build_args+=(--debug)
|
||||||
|
fi
|
||||||
|
|
||||||
|
${{ inputs.workingDirectory }}/.github/scripts/package-linux.sh "${package_args[@]}"
|
||||||
|
|
||||||
|
- name: Run Windows packaging
|
||||||
|
if: ${{ runner.os == 'Windows' }}
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$PackageArgs = @{
|
||||||
|
Target = '${{ inputs.target }}'
|
||||||
|
Configuration = '${{ inputs.config }}'
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( '${{ inputs.createInstaller }}' -eq 'true' ) {
|
||||||
|
$PackageArgs += @{BuildInstaller = $true}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( Test-Path env:CI ) -and ( Test-Path env:RUNNER_DEBUG ) ) {
|
||||||
|
$BuildArgs += @{
|
||||||
|
Debug = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${{ inputs.workingDirectory }}/.github/scripts/Package-Windows.ps1 @PackageArgs
|
BIN
.github/images/mediaunit_logo_black.png
vendored
Normal file
BIN
.github/images/mediaunit_logo_black.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
BIN
.github/images/supportclass_logo_blacktext.png
vendored
Normal file
BIN
.github/images/supportclass_logo_blacktext.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.8 KiB |
35
.github/pull_request_template.md
vendored
Normal file
35
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<!--- Please fill out the following template, which will help other contributors review your Pull Request. -->
|
||||||
|
|
||||||
|
<!--- Make sure you’ve read the contribution guidelines here: https://github.com/Palakis/obs-websocket/blob/4.x-current/CONTRIBUTING.md -->
|
||||||
|
|
||||||
|
### Description
|
||||||
|
<!--- Describe your changes. -->
|
||||||
|
|
||||||
|
### Motivation and Context
|
||||||
|
<!--- Why is this change required? What problem does it solve? -->
|
||||||
|
<!--- If it fixes/closes an open issue or implements feature request, -->
|
||||||
|
<!--- please link to the issue here. -->
|
||||||
|
|
||||||
|
### How Has This Been Tested?
|
||||||
|
<!--- Please describe in detail how you tested your changes, along with the OS(s) you tested with. -->
|
||||||
|
Tested OS(s):
|
||||||
|
|
||||||
|
### Types of changes
|
||||||
|
<!--- What types of changes does your PR introduce? Uncomment all that apply -->
|
||||||
|
|
||||||
|
<!--- - Bug fix (non-breaking change which fixes an issue) -->
|
||||||
|
<!--- - New request/event (non-breaking) -->
|
||||||
|
<!--- - Documentation change (a change to documentation pages) -->
|
||||||
|
<!--- - Enhancement (modification to a current event/request which adds functionality) -->
|
||||||
|
<!--- - Performance enhancement (non-breaking change which improves efficiency) -->
|
||||||
|
<!--- - Code cleanup (non-breaking change which makes code smaller or more readable) -->
|
||||||
|
|
||||||
|
### Checklist:
|
||||||
|
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
||||||
|
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
||||||
|
- [ ] I have read the [**contributing** document](https://github.com/Palakis/obs-websocket/blob/4.x-current/CONTRIBUTING.md).
|
||||||
|
- [ ] My code is not on the master branch.
|
||||||
|
- [ ] The code has been tested.
|
||||||
|
- [ ] All commit messages are properly formatted and commits squashed where appropriate.
|
||||||
|
- [ ] I have included updates to all appropriate documentation.
|
||||||
|
|
9
.github/scripts/.Aptfile
vendored
Normal file
9
.github/scripts/.Aptfile
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package 'cmake'
|
||||||
|
package 'ccache'
|
||||||
|
package 'curl'
|
||||||
|
package 'git'
|
||||||
|
package 'jq'
|
||||||
|
package 'ninja-build', bin: 'ninja'
|
||||||
|
package 'pkg-config'
|
||||||
|
package 'clang'
|
||||||
|
package 'clang-format-13'
|
6
.github/scripts/.Brewfile
vendored
Normal file
6
.github/scripts/.Brewfile
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
brew "ccache"
|
||||||
|
brew "coreutils"
|
||||||
|
brew "cmake"
|
||||||
|
brew "git"
|
||||||
|
brew "jq"
|
||||||
|
brew "ninja"
|
3
.github/scripts/.Wingetfile
vendored
Normal file
3
.github/scripts/.Wingetfile
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package '7zip.7zip', path: '7-zip', bin: '7z'
|
||||||
|
package 'cmake', path: 'Cmake\bin', bin: 'cmake'
|
||||||
|
package 'innosetup', path: 'Inno Setup 6', bin: 'iscc'
|
245
.github/scripts/.build.zsh
vendored
Executable file
245
.github/scripts/.build.zsh
vendored
Executable file
@ -0,0 +1,245 @@
|
|||||||
|
#!/usr/bin/env zsh
|
||||||
|
|
||||||
|
builtin emulate -L zsh
|
||||||
|
setopt EXTENDED_GLOB
|
||||||
|
setopt PUSHD_SILENT
|
||||||
|
setopt ERR_EXIT
|
||||||
|
setopt ERR_RETURN
|
||||||
|
setopt NO_UNSET
|
||||||
|
setopt PIPE_FAIL
|
||||||
|
setopt NO_AUTO_PUSHD
|
||||||
|
setopt NO_PUSHD_IGNORE_DUPS
|
||||||
|
setopt FUNCTION_ARGZERO
|
||||||
|
|
||||||
|
## Enable for script debugging
|
||||||
|
# setopt WARN_CREATE_GLOBAL
|
||||||
|
# setopt WARN_NESTED_VAR
|
||||||
|
# setopt XTRACE
|
||||||
|
|
||||||
|
autoload -Uz is-at-least && if ! is-at-least 5.2; then
|
||||||
|
print -u2 -PR "%F{1}${funcstack[1]##*/}:%f Running on Zsh version %B${ZSH_VERSION}%b, but Zsh %B5.2%b is the minimum supported version. Upgrade Zsh to fix this issue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_trap_error() {
|
||||||
|
print -u2 -PR '%F{1} ✖︎ script execution error%f'
|
||||||
|
print -PR -e "
|
||||||
|
Callstack:
|
||||||
|
${(j:\n :)funcfiletrace}
|
||||||
|
"
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
if (( ! ${+SCRIPT_HOME} )) typeset -g SCRIPT_HOME=${ZSH_ARGZERO:A:h}
|
||||||
|
local host_os=${${(s:-:)ZSH_ARGZERO:t:r}[2]}
|
||||||
|
local target="${host_os}-${CPUTYPE}"
|
||||||
|
local project_root=${SCRIPT_HOME:A:h:h}
|
||||||
|
local buildspec_file="${project_root}/buildspec.json"
|
||||||
|
|
||||||
|
trap '_trap_error' ZERR
|
||||||
|
|
||||||
|
fpath=("${SCRIPT_HOME}/utils.zsh" ${fpath})
|
||||||
|
autoload -Uz log_info log_error log_output set_loglevel check_${host_os} setup_${host_os} setup_obs setup_ccache
|
||||||
|
|
||||||
|
if [[ ! -r ${buildspec_file} ]] {
|
||||||
|
log_error \
|
||||||
|
'No buildspec.json found. Please create a build specification for your project.' \
|
||||||
|
'A buildspec.json.template file is provided in the repository to get you started.'
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
typeset -g -a skips=()
|
||||||
|
local -i _verbosity=1
|
||||||
|
local -r _version='1.0.0'
|
||||||
|
local -r -a _valid_targets=(
|
||||||
|
macos-x86_64
|
||||||
|
macos-arm64
|
||||||
|
macos-universal
|
||||||
|
linux-x86_64
|
||||||
|
)
|
||||||
|
local -r -a _valid_configs=(Debug RelWithDebInfo Release MinSizeRel)
|
||||||
|
if [[ ${host_os} == 'macos' ]] {
|
||||||
|
local -r -a _valid_generators=(Xcode Ninja 'Unix Makefiles')
|
||||||
|
} else {
|
||||||
|
local -r -a _valid_generators=(Ninja 'Unix Makefiles')
|
||||||
|
}
|
||||||
|
local generator='Ninja'
|
||||||
|
local -r _usage="
|
||||||
|
Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||||
|
|
||||||
|
%BOptions%b:
|
||||||
|
|
||||||
|
%F{yellow} Build configuration options%f
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
%B-t | --target%b Specify target - default: %B%F{green}${host_os}-${CPUTYPE}%f%b
|
||||||
|
%B-c | --config%b Build configuration - default: %B%F{green}RelWithDebInfo%f%b
|
||||||
|
%B-s | --codesign%b Enable codesigning (macOS only)
|
||||||
|
%B--generator%b Specify build system to generate - default: %B%F{green}Ninja%f%b
|
||||||
|
Available generators:
|
||||||
|
- Ninja
|
||||||
|
- Unix Makefiles
|
||||||
|
- Xcode (macOS only)
|
||||||
|
|
||||||
|
%F{yellow} Output options%f
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
%B-q | --quiet%b Quiet (error output only)
|
||||||
|
%B-v | --verbose%b Verbose (more detailed output)
|
||||||
|
%B--skip-[all|build|deps|unpack]%b Skip all|building OBS|checking for dependencies|unpacking dependencies
|
||||||
|
%B--debug%b Debug (very detailed and added output)
|
||||||
|
|
||||||
|
%F{yellow} General options%f
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
%B-h | --help%b Print this usage help
|
||||||
|
%B-V | --version%b Print script version information"
|
||||||
|
|
||||||
|
local -a args
|
||||||
|
while (( # )) {
|
||||||
|
case ${1} {
|
||||||
|
-t|--target|-c|--config|--generator)
|
||||||
|
if (( # == 1 )) || [[ ${2:0:1} == '-' ]] {
|
||||||
|
log_error "Missing value for option %B${1}%b"
|
||||||
|
log_output ${_usage}
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
;;
|
||||||
|
}
|
||||||
|
case ${1} {
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
args+=($@)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
-t|--target)
|
||||||
|
if (( ! ${_valid_targets[(Ie)${2}]} )) {
|
||||||
|
log_error "Invalid value %B${2}%b for option %B${1}%b"
|
||||||
|
log_output ${_usage}
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
target=${2}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-c|--config)
|
||||||
|
if (( ! ${_valid_configs[(Ie)${2}]} )) {
|
||||||
|
log_error "Invalid value %B${2}%b for option %B${1}%b"
|
||||||
|
log_output ${_usage}
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
BUILD_CONFIG=${2}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-s|--codesign) CODESIGN=1; shift ;;
|
||||||
|
-q|--quiet) (( _verbosity -= 1 )) || true; shift ;;
|
||||||
|
-v|--verbose) (( _verbosity += 1 )); shift ;;
|
||||||
|
-h|--help) log_output ${_usage}; exit 0 ;;
|
||||||
|
-V|--version) print -Pr "${_version}"; exit 0 ;;
|
||||||
|
--debug) _verbosity=3; shift ;;
|
||||||
|
--generator)
|
||||||
|
if (( ! ${_valid_generators[(Ie)${2}]} )) {
|
||||||
|
log_error "Invalid value %B${2}%b for option %B${1}%b"
|
||||||
|
log_output ${_usage}
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
generator=${2}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--skip-*)
|
||||||
|
local _skip="${${(s:-:)1}[-1]}"
|
||||||
|
local _check=(all deps unpack build)
|
||||||
|
(( ${_check[(Ie)${_skip}]} )) || log_warning "Invalid skip mode %B${_skip}%b supplied"
|
||||||
|
typeset -g -a skips=(${skips} ${_skip})
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*) log_error "Unknown option: %B${1}%b"; log_output ${_usage}; exit 2 ;;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set -- ${(@)args}
|
||||||
|
set_loglevel ${_verbosity}
|
||||||
|
|
||||||
|
check_${host_os}
|
||||||
|
setup_ccache
|
||||||
|
|
||||||
|
typeset -g QT_VERSION
|
||||||
|
typeset -g DEPLOYMENT_TARGET
|
||||||
|
typeset -g OBS_DEPS_VERSION
|
||||||
|
setup_${host_os}
|
||||||
|
|
||||||
|
local product_name
|
||||||
|
local product_version
|
||||||
|
read -r product_name product_version <<< \
|
||||||
|
"$(jq -r '. | {name, version} | join(" ")' ${buildspec_file})"
|
||||||
|
|
||||||
|
case ${host_os} {
|
||||||
|
macos)
|
||||||
|
sed -i '' \
|
||||||
|
"s/project(\(.*\) VERSION \(.*\))/project(${product_name} VERSION ${product_version})/" \
|
||||||
|
"${project_root}/CMakeLists.txt"
|
||||||
|
;;
|
||||||
|
linux)
|
||||||
|
sed -i'' \
|
||||||
|
"s/project(\(.*\) VERSION \(.*\))/project(${product_name} VERSION ${product_version})/"\
|
||||||
|
"${project_root}/CMakeLists.txt"
|
||||||
|
;;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_obs
|
||||||
|
|
||||||
|
pushd ${project_root}
|
||||||
|
if (( ! (${skips[(Ie)all]} + ${skips[(Ie)build]}) )) {
|
||||||
|
log_info "Configuring ${product_name}..."
|
||||||
|
|
||||||
|
local _plugin_deps="${project_root:h}/obs-build-dependencies/plugin-deps-${OBS_DEPS_VERSION}-qt${QT_VERSION}-${target##*-}"
|
||||||
|
local -a cmake_args=(
|
||||||
|
-DCMAKE_BUILD_TYPE=${BUILD_CONFIG:-RelWithDebInfo}
|
||||||
|
-DQT_VERSION=${QT_VERSION}
|
||||||
|
-DCMAKE_PREFIX_PATH="${_plugin_deps}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (( _loglevel == 0 )) cmake_args+=(-Wno_deprecated -Wno-dev --log-level=ERROR)
|
||||||
|
if (( _logLevel > 2 )) cmake_args+=(--debug-output)
|
||||||
|
|
||||||
|
local num_procs
|
||||||
|
|
||||||
|
case ${target} {
|
||||||
|
macos-*)
|
||||||
|
autoload -Uz read_codesign
|
||||||
|
if (( ${+CODESIGN} )) {
|
||||||
|
read_codesign
|
||||||
|
}
|
||||||
|
|
||||||
|
cmake_args+=(
|
||||||
|
-DCMAKE_FRAMEWORK_PATH="${_plugin_deps}/Frameworks"
|
||||||
|
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
|
||||||
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||||
|
-DOBS_CODESIGN_LINKER=ON
|
||||||
|
-DOBS_BUNDLE_CODESIGN_IDENTITY="${CODESIGN_IDENT:--}"
|
||||||
|
)
|
||||||
|
num_procs=$(( $(sysctl -n hw.ncpu) + 1 ))
|
||||||
|
;;
|
||||||
|
linux-*)
|
||||||
|
if (( ${+CI} )) {
|
||||||
|
cmake_args+=(-DCMAKE_INSTALL_PREFIX=/usr)
|
||||||
|
}
|
||||||
|
num_procs=$(( $(nproc) + 1 ))
|
||||||
|
;;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug "Attempting to configure ${product_name} with CMake arguments: ${cmake_args}"
|
||||||
|
cmake -S . -B build_${target##*-} -G ${generator} ${cmake_args}
|
||||||
|
|
||||||
|
log_info "Building ${product_name}..."
|
||||||
|
local -a cmake_args=()
|
||||||
|
if (( _loglevel > 1 )) cmake_args+=(--verbose)
|
||||||
|
if [[ ${generator} == 'Unix Makefiles' ]] cmake_args+=(--parallel ${num_procs})
|
||||||
|
cmake --build build_${target##*-} --config ${BUILD_CONFIG:-RelWithDebInfo} ${cmake_args}
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info "Installing ${product_name}..."
|
||||||
|
local -a cmake_args=()
|
||||||
|
if (( _loglevel > 1 )) cmake_args+=(--verbose)
|
||||||
|
cmake --install build_${target##*-} --config ${BUILD_CONFIG:-RelWithDebInfo} --prefix "${project_root}/release" ${cmake_args}
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
build ${@}
|
192
.github/scripts/.package.zsh
vendored
Executable file
192
.github/scripts/.package.zsh
vendored
Executable file
@ -0,0 +1,192 @@
|
|||||||
|
#!/usr/bin/env zsh
|
||||||
|
|
||||||
|
builtin emulate -L zsh
|
||||||
|
setopt EXTENDED_GLOB
|
||||||
|
setopt PUSHD_SILENT
|
||||||
|
setopt ERR_EXIT
|
||||||
|
setopt ERR_RETURN
|
||||||
|
setopt NO_UNSET
|
||||||
|
setopt PIPE_FAIL
|
||||||
|
setopt NO_AUTO_PUSHD
|
||||||
|
setopt NO_PUSHD_IGNORE_DUPS
|
||||||
|
setopt FUNCTION_ARGZERO
|
||||||
|
|
||||||
|
## Enable for script debugging
|
||||||
|
# setopt WARN_CREATE_GLOBAL
|
||||||
|
# setopt WARN_NESTED_VAR
|
||||||
|
# setopt XTRACE
|
||||||
|
|
||||||
|
autoload -Uz is-at-least && if ! is-at-least 5.2; then
|
||||||
|
print -u2 -PR "%F{1}${funcstack[1]##*/}:%f Running on Zsh version %B${ZSH_VERSION}%b, but Zsh %B5.2%b is the minimum supported version. Upgrade Zsh to fix this issue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_trap_error() {
|
||||||
|
print -u2 -PR '%F{1} ✖︎ script execution error%f'
|
||||||
|
print -PR -e "
|
||||||
|
Callstack:
|
||||||
|
${(j:\n :)funcfiletrace}
|
||||||
|
"
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
if (( ! ${+SCRIPT_HOME} )) typeset -g SCRIPT_HOME=${ZSH_ARGZERO:A:h}
|
||||||
|
local host_os=${${(s:-:)ZSH_ARGZERO:t:r}[2]}
|
||||||
|
local target="${host_os}-${CPUTYPE}"
|
||||||
|
local project_root=${SCRIPT_HOME:A:h:h}
|
||||||
|
local buildspec_file="${project_root}/buildspec.json"
|
||||||
|
trap '_trap_error' ZERR
|
||||||
|
|
||||||
|
fpath=("${SCRIPT_HOME}/utils.zsh" ${fpath})
|
||||||
|
autoload -Uz set_loglevel log_info log_error log_output check_${host_os}
|
||||||
|
|
||||||
|
local -i _verbosity=1
|
||||||
|
local -r _version='1.0.0'
|
||||||
|
local -r -a _valid_targets=(
|
||||||
|
macos-x86_64
|
||||||
|
macos-arm64
|
||||||
|
macos-universal
|
||||||
|
linux-x86_64
|
||||||
|
)
|
||||||
|
local -r -a _valid_configs=(Debug RelWithDebInfo Release MinSizeRel)
|
||||||
|
local -r _usage="
|
||||||
|
Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||||
|
|
||||||
|
%BOptions%b:
|
||||||
|
|
||||||
|
%F{yellow} Package configuration options%f
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
%B-t | --target%b Specify target - default: %B%F{green}${host_os}-${CPUTYPE}%f%b
|
||||||
|
%B-c | --config%b Build configuration - default: %B%F{green}RelWithDebInfo%f%b
|
||||||
|
%B-s | --codesign%b Enable codesigning (macOS only)
|
||||||
|
%B-n | --notarize%b Enable notarization (macOS only)
|
||||||
|
|
||||||
|
%F{yellow} Output options%f
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
%B-q | --quiet%b Quiet (error output only)
|
||||||
|
%B-v | --verbose%b Verbose (more detailed output)
|
||||||
|
%B--debug%b Debug (very detailed and added output)
|
||||||
|
|
||||||
|
%F{yellow} General options%f
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
%B-h | --help%b Print this usage help
|
||||||
|
%B-V | --version%b Print script version information"
|
||||||
|
|
||||||
|
local -a args
|
||||||
|
while (( # )) {
|
||||||
|
case ${1} {
|
||||||
|
-t|--target|-c|--config)
|
||||||
|
if (( # == 1 )) || [[ ${2:0:1} == '-' ]] {
|
||||||
|
log_error "Missing value for option %B${1}%b"
|
||||||
|
log_output ${_usage}
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
;;
|
||||||
|
}
|
||||||
|
case ${1} {
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
args+=($@)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
-t|--target)
|
||||||
|
if (( ! ${_valid_targets[(Ie)${2}]} )) {
|
||||||
|
log_error "Invalid value %B${2}%b for option %B${1}%b"
|
||||||
|
log_output ${_usage}
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
target=${2}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-c|--config)
|
||||||
|
if (( ! ${_valid_configs[(Ie)${2}]} )) {
|
||||||
|
log_error "Invalid value %B${2}%b for option %B${1}%b"
|
||||||
|
log_output ${_usage}
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
BUILD_CONFIG=${2}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-s|--codesign) typeset -g CODESIGN=1; shift ;;
|
||||||
|
-n|--notarize) typeset -g NOTARIZE=1; typeset -g CODESIGN=1; shift ;;
|
||||||
|
-q|--quiet) (( _verbosity -= 1 )) || true; shift ;;
|
||||||
|
-v|--verbose) (( _verbosity += 1 )); shift ;;
|
||||||
|
-h|--help) log_output ${_usage}; exit 0 ;;
|
||||||
|
-V|--version) print -Pr "${_version}"; exit 0 ;;
|
||||||
|
--debug) _verbosity=3; shift ;;
|
||||||
|
*) log_error "Unknown option: %B${1}%b"; log_output ${_usage}; exit 2 ;;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set -- ${(@)args}
|
||||||
|
set_loglevel ${_verbosity}
|
||||||
|
|
||||||
|
check_${host_os}
|
||||||
|
|
||||||
|
local product_name
|
||||||
|
local product_version
|
||||||
|
read -r product_name product_version <<< \
|
||||||
|
"$(jq -r '. | {name, version} | join(" ")' ${project_root}/buildspec.json)"
|
||||||
|
|
||||||
|
if [[ ${host_os} == 'macos' ]] {
|
||||||
|
autoload -Uz check_packages read_codesign read_codesign_installer read_codesign_pass
|
||||||
|
|
||||||
|
local output_name="${product_name}-${product_version}-${host_os}-${target##*-}.pkg"
|
||||||
|
|
||||||
|
if [[ ! -d ${project_root}/release/${product_name}.plugin ]] {
|
||||||
|
log_error 'No release artifact found. Run the build script or the CMake install procedure first.'
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ ! -f ${project_root}/build_${target##*-}/installer-macos.generated.pkgproj ]] {
|
||||||
|
log_error 'Packages project file not found. Run the build script or the CMake build and install procedures first.'
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
check_packages
|
||||||
|
|
||||||
|
log_info "Packaging ${product_name}..."
|
||||||
|
pushd ${project_root}
|
||||||
|
packagesbuild \
|
||||||
|
--build-folder ${project_root}/release \
|
||||||
|
${project_root}/build_${target##*-}/installer-macos.generated.pkgproj
|
||||||
|
|
||||||
|
if (( ${+CODESIGN} )) {
|
||||||
|
read_codesign_installer
|
||||||
|
productsign \
|
||||||
|
--sign "${CODESIGN_IDENT_INSTALLER}" \
|
||||||
|
"${project_root}/release/${product_name}.pkg" \
|
||||||
|
"${project_root}/release/${output_name}"
|
||||||
|
|
||||||
|
rm "${project_root}/release/${product_name}.pkg"
|
||||||
|
} else {
|
||||||
|
mv "${project_root}/release/${product_name}.pkg" \
|
||||||
|
"${project_root}/release/${output_name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( ${+CODESIGN} && ${+NOTARIZE} )) {
|
||||||
|
if [[ ! -f "${project_root}/release/${output_name}" ]] {
|
||||||
|
log_error "No package for notarization found."
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
read_codesign_installer
|
||||||
|
read_codesign_pass
|
||||||
|
|
||||||
|
xcrun notarytool submit "${project_root}/release/${output_name}" \
|
||||||
|
--keychain-profile "OBS-Codesign-Password" --wait
|
||||||
|
xcrun stapler staple "${project_root}/release/${output_name}"
|
||||||
|
}
|
||||||
|
popd
|
||||||
|
} elif [[ ${host_os} == 'linux' ]] {
|
||||||
|
local -a cmake_args=()
|
||||||
|
if (( _loglevel > 1 )) cmake_args+=(--verbose)
|
||||||
|
|
||||||
|
pushd ${project_root}
|
||||||
|
cmake --build build_${target##*-} --config ${BUILD_CONFIG:-RelWithDebInfo} -t package ${cmake_args}
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
package ${@}
|
101
.github/scripts/Build-Windows.ps1
vendored
Normal file
101
.github/scripts/Build-Windows.ps1
vendored
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[ValidateSet('Debug', 'RelWithDebInfo', 'Release', 'MinSizeRel')]
|
||||||
|
[string] $Configuration = 'RelWithDebInfo',
|
||||||
|
[ValidateSet('x86', 'x64')]
|
||||||
|
[string] $Target,
|
||||||
|
[ValidateSet('Visual Studio 17 2022', 'Visual Studio 16 2019')]
|
||||||
|
[string] $CMakeGenerator,
|
||||||
|
[switch] $SkipAll,
|
||||||
|
[switch] $SkipBuild,
|
||||||
|
[switch] $SkipDeps,
|
||||||
|
[switch] $SkipUnpack
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
if ( $DebugPreference -eq 'Continue' ) {
|
||||||
|
$VerbosePreference = 'Continue'
|
||||||
|
$InformationPreference = 'Continue'
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $PSVersionTable.PSVersion -lt '7.0.0' ) {
|
||||||
|
Write-Warning 'The obs-deps PowerShell build script requires PowerShell Core 7. Install or upgrade your PowerShell version: https://aka.ms/pscore6'
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
function Build {
|
||||||
|
trap {
|
||||||
|
Pop-Location -Stack BuildTemp
|
||||||
|
Write-Error $_
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
$ScriptHome = $PSScriptRoot
|
||||||
|
$ProjectRoot = Resolve-Path -Path "$PSScriptRoot/../.."
|
||||||
|
$BuildSpecFile = "${ProjectRoot}/buildspec.json"
|
||||||
|
|
||||||
|
$UtilityFunctions = Get-ChildItem -Path $PSScriptRoot/utils.pwsh/*.ps1 -Recurse
|
||||||
|
|
||||||
|
foreach($Utility in $UtilityFunctions) {
|
||||||
|
Write-Debug "Loading $($Utility.FullName)"
|
||||||
|
. $Utility.FullName
|
||||||
|
}
|
||||||
|
|
||||||
|
$BuildSpec = Get-Content -Path ${BuildSpecFile} -Raw | ConvertFrom-Json
|
||||||
|
$ProductName = $BuildSpec.name
|
||||||
|
$ProductVersion = $BuildSpec.version
|
||||||
|
|
||||||
|
$script:DepsVersion = ''
|
||||||
|
$script:QtVersion = '5'
|
||||||
|
$script:VisualStudioVersion = ''
|
||||||
|
$script:PlatformSDK = '10.0.18363.657'
|
||||||
|
|
||||||
|
Setup-Host
|
||||||
|
|
||||||
|
if ( $CmakeGenerator -eq '' ) {
|
||||||
|
$CmakeGenerator = $VisualStudioVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
(Get-Content -Path ${ProjectRoot}/CMakeLists.txt -Raw) `
|
||||||
|
-replace "project\((.*) VERSION (.*)\)", "project(${ProductName} VERSION ${ProductVersion})" `
|
||||||
|
| Out-File -Path ${ProjectRoot}/CMakeLists.txt
|
||||||
|
|
||||||
|
Setup-Obs
|
||||||
|
|
||||||
|
Push-Location -Stack BuildTemp
|
||||||
|
if ( ! ( ( $SkipAll ) -or ( $SkipBuild ) ) ) {
|
||||||
|
Ensure-Location $ProjectRoot
|
||||||
|
|
||||||
|
$DepsPath = "plugin-deps-${script:DepsVersion}-qt${script:QtVersion}-${script:Target}"
|
||||||
|
$CmakeArgs = @(
|
||||||
|
'-G', $CmakeGenerator
|
||||||
|
"-DCMAKE_SYSTEM_VERSION=${script:PlatformSDK}"
|
||||||
|
"-DCMAKE_GENERATOR_PLATFORM=$(if (${script:Target} -eq "x86") { "Win32" } else { "x64" })"
|
||||||
|
"-DCMAKE_BUILD_TYPE=${Configuration}"
|
||||||
|
"-DCMAKE_PREFIX_PATH:PATH=$(Resolve-Path -Path "${ProjectRoot}/../obs-build-dependencies/${DepsPath}")"
|
||||||
|
"-DQT_VERSION=${script:QtVersion}"
|
||||||
|
)
|
||||||
|
|
||||||
|
Log-Debug "Attempting to configure OBS with CMake arguments: $($CmakeArgs | Out-String)"
|
||||||
|
Log-Information "Configuring ${ProductName}..."
|
||||||
|
Invoke-External cmake -S . -B build_${script:Target} @CmakeArgs
|
||||||
|
|
||||||
|
$CmakeArgs = @(
|
||||||
|
'--config', "${Configuration}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if ( $VerbosePreference -eq 'Continue' ) {
|
||||||
|
$CmakeArgs+=('--verbose')
|
||||||
|
}
|
||||||
|
|
||||||
|
Log-Information "Building ${ProductName}..."
|
||||||
|
Invoke-External cmake --build "build_${script:Target}" @CmakeArgs
|
||||||
|
}
|
||||||
|
Log-Information "Install ${ProductName}..."
|
||||||
|
Invoke-External cmake --install "build_${script:Target}" --prefix "${ProjectRoot}/release" @CmakeArgs
|
||||||
|
|
||||||
|
Pop-Location -Stack BuildTemp
|
||||||
|
}
|
||||||
|
|
||||||
|
Build
|
92
.github/scripts/Package-Windows.ps1
vendored
Normal file
92
.github/scripts/Package-Windows.ps1
vendored
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[ValidateSet('Debug', 'RelWithDebInfo', 'Release', 'MinSizeRel')]
|
||||||
|
[string] $Configuration = 'RelWithDebInfo',
|
||||||
|
[ValidateSet('x86', 'x64', 'x86+x64')]
|
||||||
|
[string] $Target,
|
||||||
|
[switch] $BuildInstaller = $false
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
if ( $DebugPreference -eq 'Continue' ) {
|
||||||
|
$VerbosePreference = 'Continue'
|
||||||
|
$InformationPreference = 'Continue'
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $PSVersionTable.PSVersion -lt '7.0.0' ) {
|
||||||
|
Write-Warning 'The obs-deps PowerShell build script requires PowerShell Core 7. Install or upgrade your PowerShell version: https://aka.ms/pscore6'
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
function Package {
|
||||||
|
trap {
|
||||||
|
Write-Error $_
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
$ScriptHome = $PSScriptRoot
|
||||||
|
$ProjectRoot = Resolve-Path -Path "$PSScriptRoot/../.."
|
||||||
|
$BuildSpecFile = "${ProjectRoot}/buildspec.json"
|
||||||
|
|
||||||
|
$UtilityFunctions = Get-ChildItem -Path $PSScriptRoot/utils.pwsh/*.ps1 -Recurse
|
||||||
|
|
||||||
|
foreach( $Utility in $UtilityFunctions ) {
|
||||||
|
Write-Debug "Loading $($Utility.FullName)"
|
||||||
|
. $Utility.FullName
|
||||||
|
}
|
||||||
|
|
||||||
|
$BuildSpec = Get-Content -Path ${BuildSpecFile} -Raw | ConvertFrom-Json
|
||||||
|
$ProductName = $BuildSpec.name
|
||||||
|
$ProductVersion = $BuildSpec.version
|
||||||
|
|
||||||
|
$OutputName = "${ProductName}-${ProductVersion}-windows-${Target}"
|
||||||
|
|
||||||
|
Install-BuildDependencies -WingetFile "${ScriptHome}/.Wingetfile"
|
||||||
|
|
||||||
|
Log-Information "Packaging ${ProductName}..."
|
||||||
|
|
||||||
|
$RemoveArgs = @{
|
||||||
|
ErrorAction = 'SilentlyContinue'
|
||||||
|
Path = @(
|
||||||
|
"${ProjectRoot}/release/${ProductName}-*-windows-*.zip"
|
||||||
|
"${ProjectRoot}/release/${ProductName}-*-windows-*.exe"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Remove-Item @RemoveArgs
|
||||||
|
|
||||||
|
if ( ( $BuildInstaller ) ) {
|
||||||
|
if ( $Target -eq 'x86+x64' ) {
|
||||||
|
$IsccCandidates = Get-ChildItem -Recurse -Path '*.iss'
|
||||||
|
|
||||||
|
if ( $IsccCandidates.length -gt 0 ) {
|
||||||
|
$IsccFile = $IsccCandidates[0].FullName
|
||||||
|
} else {
|
||||||
|
$IsccFile = ''
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$IsccFile = "${ProjectRoot}/build_${Target}/installer-Windows.generated.iss"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ( Test-Path -Path $IsccFile ) ) {
|
||||||
|
throw 'InnoSetup install script not found. Run the build script or the CMake build and install procedures first.'
|
||||||
|
}
|
||||||
|
|
||||||
|
Log-Information 'Creating InnoSetup installer...'
|
||||||
|
Push-Location -Stack BuildTemp
|
||||||
|
Ensure-Location -Path "${ProjectRoot}/release"
|
||||||
|
Invoke-External iscc ${IsccFile} /O. /F"${OutputName}-Installer"
|
||||||
|
Pop-Location -Stack BuildTemp
|
||||||
|
}
|
||||||
|
|
||||||
|
$CompressArgs = @{
|
||||||
|
Path = (Get-ChildItem -Path "${ProjectRoot}/release" -Exclude "${OutputName}*.*")
|
||||||
|
CompressionLevel = 'Optimal'
|
||||||
|
DestinationPath = "${ProjectRoot}/release/${OutputName}.zip"
|
||||||
|
}
|
||||||
|
|
||||||
|
Compress-Archive -Force @CompressArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
Package
|
13
.github/scripts/build-linux.sh
vendored
Executable file
13
.github/scripts/build-linux.sh
vendored
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if ! type zsh > /dev/null 2>&1; then
|
||||||
|
echo ' => Installing script dependency Zsh.'
|
||||||
|
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install zsh
|
||||||
|
fi
|
||||||
|
|
||||||
|
SCRIPT=$(readlink -f "${0}")
|
||||||
|
SCRIPT_DIR=$(dirname "${SCRIPT}")
|
||||||
|
|
||||||
|
zsh ${SCRIPT_DIR}/build-linux.zsh "${@}"
|
1
.github/scripts/build-linux.zsh
vendored
Symbolic link
1
.github/scripts/build-linux.zsh
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
.build.zsh
|
1
.github/scripts/build-macos.zsh
vendored
Symbolic link
1
.github/scripts/build-macos.zsh
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
.build.zsh
|
11
.github/scripts/check-changes.sh
vendored
Executable file
11
.github/scripts/check-changes.sh
vendored
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
dirty=$(git ls-files --modified)
|
||||||
|
|
||||||
|
set +x
|
||||||
|
if [[ $dirty ]]; then
|
||||||
|
echo "================================="
|
||||||
|
echo "Files were not formatted properly"
|
||||||
|
echo "$dirty"
|
||||||
|
echo "================================="
|
||||||
|
exit 1
|
||||||
|
fi
|
45
.github/scripts/check-cmake.sh
vendored
Executable file
45
.github/scripts/check-cmake.sh
vendored
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
if [ ${#} -eq 1 -a "${1}" = "VERBOSE" ]; then
|
||||||
|
VERBOSITY="-l debug"
|
||||||
|
else
|
||||||
|
VERBOSITY=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${CI}" ]; then
|
||||||
|
MODE="--check"
|
||||||
|
else
|
||||||
|
MODE="-i"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Runs the formatter in parallel on the code base.
|
||||||
|
# Return codes:
|
||||||
|
# - 1 there are files to be formatted
|
||||||
|
# - 0 everything looks fine
|
||||||
|
|
||||||
|
# Get CPU count
|
||||||
|
OS=$(uname)
|
||||||
|
NPROC=1
|
||||||
|
if [[ ${OS} = "Linux" ]] ; then
|
||||||
|
NPROC=$(nproc)
|
||||||
|
elif [[ ${OS} = "Darwin" ]] ; then
|
||||||
|
NPROC=$(sysctl -n hw.physicalcpu)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Discover clang-format
|
||||||
|
if ! type cmake-format 2> /dev/null ; then
|
||||||
|
echo "Required cmake-format not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
find . -type d \( \
|
||||||
|
-path ./\*build -o \
|
||||||
|
-path ./release -o \
|
||||||
|
-path ./deps \
|
||||||
|
\) -prune -false -type f -o \
|
||||||
|
-name 'CMakeLists.txt' -or \
|
||||||
|
-name '*.cmake' \
|
||||||
|
| xargs -L10 -P ${NPROC} cmake-format ${MODE} ${VERBOSITY}
|
56
.github/scripts/check-format.sh
vendored
Executable file
56
.github/scripts/check-format.sh
vendored
Executable file
@ -0,0 +1,56 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Original source https://github.com/Project-OSRM/osrm-backend/blob/master/scripts/format.sh
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
if [ ${#} -eq 1 ]; then
|
||||||
|
VERBOSITY="--verbose"
|
||||||
|
else
|
||||||
|
VERBOSITY=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Runs the Clang Formatter in parallel on the code base.
|
||||||
|
# Return codes:
|
||||||
|
# - 1 there are files to be formatted
|
||||||
|
# - 0 everything looks fine
|
||||||
|
|
||||||
|
# Get CPU count
|
||||||
|
OS=$(uname)
|
||||||
|
NPROC=1
|
||||||
|
if [[ ${OS} = "Linux" ]] ; then
|
||||||
|
NPROC=$(nproc)
|
||||||
|
elif [[ ${OS} = "Darwin" ]] ; then
|
||||||
|
NPROC=$(sysctl -n hw.physicalcpu)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Discover clang-format
|
||||||
|
if type clang-format-13 2> /dev/null ; then
|
||||||
|
CLANG_FORMAT=clang-format-13
|
||||||
|
elif type clang-format 2> /dev/null ; then
|
||||||
|
# Clang format found, but need to check version
|
||||||
|
CLANG_FORMAT=clang-format
|
||||||
|
V=$(clang-format --version)
|
||||||
|
if [[ $V != *"version 13.0"* ]]; then
|
||||||
|
echo "clang-format is not 13.0 (returned ${V})"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "No appropriate clang-format found (expected clang-format-13.0.0, or clang-format)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
find . -type d \( \
|
||||||
|
-path ./\*build -o \
|
||||||
|
-path ./release -o \
|
||||||
|
-path ./cmake -o \
|
||||||
|
-path ./deps \
|
||||||
|
\) -prune -false -type f -o \
|
||||||
|
-name '*.h' -or \
|
||||||
|
-name '*.hpp' -or \
|
||||||
|
-name '*.m' -or \
|
||||||
|
-name '*.mm' -or \
|
||||||
|
-name '*.c' -or \
|
||||||
|
-name '*.cpp' \
|
||||||
|
| xargs -L100 -P ${NPROC} "${CLANG_FORMAT}" ${VERBOSITY} -i -style=file -fallback-style=none
|
13
.github/scripts/package-linux.sh
vendored
Executable file
13
.github/scripts/package-linux.sh
vendored
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if ! type zsh > /dev/null 2>&1; then
|
||||||
|
echo ' => Installing script dependency Zsh.'
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install zsh
|
||||||
|
fi
|
||||||
|
|
||||||
|
SCRIPT=$(readlink -f "${0}")
|
||||||
|
SCRIPT_DIR=$(dirname "${SCRIPT}")
|
||||||
|
|
||||||
|
zsh ${SCRIPT_DIR}/package-linux.zsh "${@}"
|
1
.github/scripts/package-linux.zsh
vendored
Symbolic link
1
.github/scripts/package-linux.zsh
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
.package.zsh
|
1
.github/scripts/package-macos.zsh
vendored
Symbolic link
1
.github/scripts/package-macos.zsh
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
.package.zsh
|
25
.github/scripts/utils.pwsh/Check-Git.ps1
vendored
Normal file
25
.github/scripts/utils.pwsh/Check-Git.ps1
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
function Check-Git {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Ensures available git executable on host system.
|
||||||
|
.DESCRIPTION
|
||||||
|
Checks whether a git command is available on the host system. If none is found,
|
||||||
|
Git is installed via winget.
|
||||||
|
.EXAMPLE
|
||||||
|
Check-Git
|
||||||
|
#>
|
||||||
|
|
||||||
|
if ( ! ( Test-Path function:Log-Info ) ) {
|
||||||
|
. $PSScriptRoot/Logger.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
Log-Information 'Checking for Git executable...'
|
||||||
|
|
||||||
|
if ( ! ( Get-Command git ) ) {
|
||||||
|
Log-Warning 'No Git executable found. Will try to install via winget.'
|
||||||
|
winget install git
|
||||||
|
} else {
|
||||||
|
Log-Debug "Git found at $(Get-Command git)."
|
||||||
|
Log-Status "Git found."
|
||||||
|
}
|
||||||
|
}
|
29
.github/scripts/utils.pwsh/Ensure-Location.ps1
vendored
Normal file
29
.github/scripts/utils.pwsh/Ensure-Location.ps1
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
function Ensure-Location {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Ensures current location to be set to specified directory.
|
||||||
|
.DESCRIPTION
|
||||||
|
If specified directory exists, switch to it. Otherwise create it,
|
||||||
|
then switch.
|
||||||
|
.EXAMPLE
|
||||||
|
Ensure-Location "My-Directory"
|
||||||
|
Ensure-Location -Path "Path-To-My-Directory"
|
||||||
|
#>
|
||||||
|
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[string] $Path
|
||||||
|
)
|
||||||
|
|
||||||
|
if ( ! ( Test-Path $Path ) ) {
|
||||||
|
$_Params = @{
|
||||||
|
ItemType = "Directory"
|
||||||
|
Path = ${Path}
|
||||||
|
ErrorAction = "SilentlyContinue"
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item @_Params | Set-Location
|
||||||
|
} else {
|
||||||
|
Set-Location -Path ${Path}
|
||||||
|
}
|
||||||
|
}
|
70
.github/scripts/utils.pwsh/Expand-ArchiveExt.ps1
vendored
Normal file
70
.github/scripts/utils.pwsh/Expand-ArchiveExt.ps1
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
function Expand-ArchiveExt {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Expands archive files.
|
||||||
|
.DESCRIPTION
|
||||||
|
Allows extraction of zip, 7z, gz, and xz archives.
|
||||||
|
Requires tar and 7-zip to be available on the system.
|
||||||
|
Archives ending with .zip but created using LZMA compression are
|
||||||
|
expanded using 7-zip as a fallback.
|
||||||
|
.EXAMPLE
|
||||||
|
Expand-ArchiveExt -Path <Path-To-Your-Archive>
|
||||||
|
Expand-ArchiveExt -Path <Path-To-Your-Archive> -DestinationPath <Expansion-Path>
|
||||||
|
#>
|
||||||
|
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[string] $Path,
|
||||||
|
[string] $DestinationPath = [System.IO.Path]::GetFileNameWithoutExtension($Path),
|
||||||
|
[switch] $Force
|
||||||
|
)
|
||||||
|
|
||||||
|
switch ( [System.IO.Path]::GetExtension($Path) ) {
|
||||||
|
.zip {
|
||||||
|
try {
|
||||||
|
Expand-Archive -Path $Path -DestinationPath $DestinationPath -Force:$Force
|
||||||
|
} catch {
|
||||||
|
if ( Get-Command 7z ) {
|
||||||
|
Invoke-External 7z x -y $Path "-o${DestinationPath}"
|
||||||
|
} else {
|
||||||
|
throw "Fallback utility 7-zip not found. Please install 7-zip first."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
{ ( $_ -eq ".7z" ) -or ( $_ -eq ".exe" ) } {
|
||||||
|
if ( Get-Command 7z ) {
|
||||||
|
Invoke-External 7z x -y $Path "-o${DestinationPath}"
|
||||||
|
} else {
|
||||||
|
throw "Extraction utility 7-zip not found. Please install 7-zip first."
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
.gz {
|
||||||
|
try {
|
||||||
|
Invoke-External tar -x -o $DestinationPath -f $Path
|
||||||
|
} catch {
|
||||||
|
if ( Get-Command 7z ) {
|
||||||
|
Invoke-External 7z x -y $Path "-o${DestinationPath}"
|
||||||
|
} else {
|
||||||
|
throw "Fallback utility 7-zip not found. Please install 7-zip first."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
.xz {
|
||||||
|
try {
|
||||||
|
Invoke-External tar -x -o $DestinationPath -f $Path
|
||||||
|
} catch {
|
||||||
|
if ( Get-Command 7z ) {
|
||||||
|
Invoke-External 7z x -y $Path "-o${DestinationPath}"
|
||||||
|
} else {
|
||||||
|
throw "Fallback utility 7-zip not found. Please install 7-zip first."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
throw "Unsupported archive extension provided."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
.github/scripts/utils.pwsh/Install-BuildDependencies.ps1
vendored
Normal file
60
.github/scripts/utils.pwsh/Install-BuildDependencies.ps1
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
function Install-BuildDependencies {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Installs required build dependencies.
|
||||||
|
.DESCRIPTION
|
||||||
|
Additional packages might be needed for successful builds. This module contains additional
|
||||||
|
dependencies available for installation via winget and, if possible, adds their locations
|
||||||
|
to the environment path for future invocation.
|
||||||
|
.EXAMPLE
|
||||||
|
Install-BuildDependencies
|
||||||
|
#>
|
||||||
|
|
||||||
|
param(
|
||||||
|
[string] $WingetFile = "$PSScriptRoot/.Wingetfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
if ( ! ( Test-Path function:Log-Warning ) ) {
|
||||||
|
. $PSScriptRoot/Logger.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
$Host64Bit = [System.Environment]::Is64BitOperatingSystem
|
||||||
|
|
||||||
|
$Paths = $Env:Path -split [System.IO.Path]::PathSeparator
|
||||||
|
|
||||||
|
$WingetOptions = @('install', '--accept-package-agreements', '--accept-source-agreements')
|
||||||
|
|
||||||
|
if ( $script:Quiet ) {
|
||||||
|
$WingetOptions += '--silent'
|
||||||
|
}
|
||||||
|
|
||||||
|
Get-Content $WingetFile | ForEach-Object {
|
||||||
|
$_, $Package, $_, $Path, $_, $Binary = ([regex]::Split($_, " (?=(?:[^']|'[^']*')*$)")) -replace ',', '' -replace "'",''
|
||||||
|
|
||||||
|
(${Env:ProgramFiles(x86)}, $Env:ProgramFiles) | ForEach-Object {
|
||||||
|
$Prefix = $_
|
||||||
|
$FullPath = "${Prefix}\${Path}"
|
||||||
|
if ( ( Test-Path $FullPath ) -and ! ( $Paths -contains $FullPath ) ) {
|
||||||
|
$Paths += $FullPath
|
||||||
|
$Env:Path = $Paths -join [System.IO.Path]::PathSeparator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log-Debug "Checking for command ${Binary}"
|
||||||
|
$Found = Get-Command -ErrorAction SilentlyContinue $Binary
|
||||||
|
|
||||||
|
if ( $Found ) {
|
||||||
|
Log-Status "Found dependency ${Binary} as $($Found.Source)"
|
||||||
|
} else {
|
||||||
|
Log-Status "Installing package ${Package}"
|
||||||
|
|
||||||
|
try {
|
||||||
|
$Params = $WingetOptions + $Package
|
||||||
|
|
||||||
|
winget @Params
|
||||||
|
} catch {
|
||||||
|
throw "Error while installing winget package ${Package}: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
.github/scripts/utils.pwsh/Invoke-External.ps1
vendored
Normal file
40
.github/scripts/utils.pwsh/Invoke-External.ps1
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
function Invoke-External {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Invokes a non-PowerShell command.
|
||||||
|
.DESCRIPTION
|
||||||
|
Runs a non-PowerShell command, and captures its return code.
|
||||||
|
Throws an exception if the command returns non-zero.
|
||||||
|
.EXAMPLE
|
||||||
|
Invoke-External 7z x $MyArchive
|
||||||
|
#>
|
||||||
|
|
||||||
|
if ( $args.Count -eq 0 ) {
|
||||||
|
throw 'Invoke-External called without arguments.'
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ( Test-Path function:Log-Information ) ) {
|
||||||
|
. $PSScriptRoot/Logger.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
$Command = $args[0]
|
||||||
|
$CommandArgs = @()
|
||||||
|
|
||||||
|
if ( $args.Count -gt 1) {
|
||||||
|
$CommandArgs = $args[1..($args.Count - 1)]
|
||||||
|
}
|
||||||
|
|
||||||
|
$_EAP = $ErrorActionPreference
|
||||||
|
$ErrorActionPreference = "Continue"
|
||||||
|
|
||||||
|
Log-Debug "Invoke-External: ${Command} ${CommandArgs}"
|
||||||
|
|
||||||
|
& $command $commandArgs
|
||||||
|
$Result = $LASTEXITCODE
|
||||||
|
|
||||||
|
$ErrorActionPreference = $_EAP
|
||||||
|
|
||||||
|
if ( $Result -ne 0 ) {
|
||||||
|
throw "${Command} ${CommandArgs} exited with non-zero code ${Result}."
|
||||||
|
}
|
||||||
|
}
|
117
.github/scripts/utils.pwsh/Invoke-GitCheckout.ps1
vendored
Normal file
117
.github/scripts/utils.pwsh/Invoke-GitCheckout.ps1
vendored
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
function Set-GitConfig {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Sets a git config value.
|
||||||
|
.DESCRIPTION
|
||||||
|
Allows setting single or multiple config values in a PowerShell-friendly fashion.
|
||||||
|
.EXAMPLE
|
||||||
|
Set-GitConfig advice.detachedHead false
|
||||||
|
#>
|
||||||
|
|
||||||
|
if ( $args.Count -lt 2 ) {
|
||||||
|
throw 'Set-GitConfig called without required arguments <OPTION> <VALUE>.'
|
||||||
|
}
|
||||||
|
|
||||||
|
Invoke-External git config @args
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-GitCheckout {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Checks out a specified git repository.
|
||||||
|
.DESCRIPTION
|
||||||
|
Wraps the git executable with PowerShell syntax to check out
|
||||||
|
a specified Git repository with a given commit hash and branch,
|
||||||
|
or a GitHub pull request ID.
|
||||||
|
.EXAMPLE
|
||||||
|
Invoke-GitCheckout -Uri "My-Repo-Uri" -Commit "My-Commit-Hash"
|
||||||
|
Invoke-GitCheckout -Uri "My-Repo-Uri" -Commit "My-Commit-Hash" -Branch "main"
|
||||||
|
Invoke-GitCheckout -Uri "My-Repo-Uri" -Commit "My-Commit-Hash" -PullRequest 250
|
||||||
|
#>
|
||||||
|
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[string] $Uri,
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[string] $Commit,
|
||||||
|
[string] $Path,
|
||||||
|
[string] $Branch = "master",
|
||||||
|
[string] $PullRequest
|
||||||
|
)
|
||||||
|
|
||||||
|
if ( ! ( $Uri -like "*github.com*" ) -and ( $PullRequest -ne "" ) ) {
|
||||||
|
throw 'Fetching pull requests is only supported with GitHub-based repositories.'
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ( Test-Path function:Log-Information ) ) {
|
||||||
|
. $PSScriptRoot/Logger.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ( Test-Path function:Invoke-External ) ) {
|
||||||
|
. $PSScriptRoot/Invoke-External.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
$RepositoryName = [System.IO.Path]::GetFileNameWithoutExtension($Uri)
|
||||||
|
|
||||||
|
if ( $Path -eq "" ) {
|
||||||
|
$Path = "$(Get-Location | Convert-Path)\${RepositoryName}"
|
||||||
|
}
|
||||||
|
|
||||||
|
Push-Location -Stack GitCheckoutTemp
|
||||||
|
|
||||||
|
if ( Test-Path $Path/.git ) {
|
||||||
|
Write-Information "Repository ${RepositoryName} found in ${Path}"
|
||||||
|
|
||||||
|
Set-Location $Path
|
||||||
|
|
||||||
|
Set-GitConfig advice.detachedHead false
|
||||||
|
Set-GitConfig remote.origin.url $Uri
|
||||||
|
Set-GitConfig remote.origin.tapOpt --no-tags
|
||||||
|
|
||||||
|
$Ref = "+refs/heads/{0}:refs/remotes/origin/{0}" -f $Branch
|
||||||
|
|
||||||
|
Set-GitConfig --replace-all remote.origin.fetch $Ref
|
||||||
|
|
||||||
|
if ( $PullRequest -ne "" ) {
|
||||||
|
try {
|
||||||
|
Invoke-External git show-ref --quiet --verify refs/heads/pr-$PullRequest
|
||||||
|
} catch {
|
||||||
|
Invoke-External git fetch origin $("pull/{0}/head:pull-{0}" -f $PullRequest)
|
||||||
|
} finally {
|
||||||
|
Invoke-External git checkout -f "pull-${PullRequest}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$null = Invoke-External git rev-parse -q --verify "${Commit}^{commit}"
|
||||||
|
} catch {
|
||||||
|
Invoke-External git fetch origin
|
||||||
|
}
|
||||||
|
|
||||||
|
Invoke-External git checkout -f $Commit -- | Log-Information
|
||||||
|
} else {
|
||||||
|
Invoke-External git clone $Uri $Path
|
||||||
|
|
||||||
|
Set-Location $Path
|
||||||
|
|
||||||
|
Set-GitConfig advice.detachedHead false
|
||||||
|
|
||||||
|
if ( $PullRequest -ne "" ) {
|
||||||
|
$Ref = "pull/{0}/head:pull-{0}" -f $PullRequest
|
||||||
|
$Branch = "pull-${PullRequest}"
|
||||||
|
Invoke-External git fetch origin $Ref
|
||||||
|
Invoke-External git checkout $Branch
|
||||||
|
}
|
||||||
|
|
||||||
|
Invoke-External git checkout -f $Commit
|
||||||
|
}
|
||||||
|
|
||||||
|
Log-Information "Checked out commit ${Commit} on branch ${Branch}"
|
||||||
|
|
||||||
|
if ( Test-Path ${Path}/.gitmodules ) {
|
||||||
|
Invoke-External git submodule foreach --recursive git submodule sync
|
||||||
|
Invoke-External git submodule update --init --recursive
|
||||||
|
}
|
||||||
|
|
||||||
|
Pop-Location -Stack GitCheckoutTemp
|
||||||
|
}
|
123
.github/scripts/utils.pwsh/Logger.ps1
vendored
Normal file
123
.github/scripts/utils.pwsh/Logger.ps1
vendored
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
function Log-Debug {
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory,ValueFromPipeline)]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[string[]] $Message
|
||||||
|
)
|
||||||
|
|
||||||
|
Process {
|
||||||
|
foreach($m in $Message) {
|
||||||
|
Write-Debug $m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Log-Verbose {
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory,ValueFromPipeline)]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[string[]] $Message
|
||||||
|
)
|
||||||
|
|
||||||
|
Process {
|
||||||
|
foreach($m in $Message) {
|
||||||
|
Write-Verbose $m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Log-Warning {
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory,ValueFromPipeline)]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[string[]] $Message
|
||||||
|
)
|
||||||
|
|
||||||
|
Process {
|
||||||
|
foreach($m in $Message) {
|
||||||
|
Write-Warning $m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Log-Error {
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory,ValueFromPipeline)]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[string[]] $Message
|
||||||
|
)
|
||||||
|
|
||||||
|
Process {
|
||||||
|
foreach($m in $Message) {
|
||||||
|
Write-Error $m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Log-Information {
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory,ValueFromPipeline)]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[string[]] $Message
|
||||||
|
)
|
||||||
|
|
||||||
|
Process {
|
||||||
|
if ( ! ( $script:Quiet ) ) {
|
||||||
|
$StageName = $( if ( $script:StageName -ne $null ) { $script:StageName } else { '' })
|
||||||
|
$Icon = ' =>'
|
||||||
|
|
||||||
|
foreach($m in $Message) {
|
||||||
|
Write-Host -NoNewLine -ForegroundColor Blue " ${StageName} $($Icon.PadRight(5)) "
|
||||||
|
Write-Host "${m}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Log-Status {
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory,ValueFromPipeline)]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[string[]] $Message
|
||||||
|
)
|
||||||
|
|
||||||
|
Process {
|
||||||
|
if ( ! ( $script:Quiet ) ) {
|
||||||
|
$StageName = $( if ( $StageName -ne $null ) { $StageName } else { '' })
|
||||||
|
$Icon = ' >'
|
||||||
|
|
||||||
|
foreach($m in $Message) {
|
||||||
|
Write-Host -NoNewLine -ForegroundColor Green " ${StageName} $($Icon.PadRight(5)) "
|
||||||
|
Write-Host "${m}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Log-Output {
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory,ValueFromPipeline)]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[string[]] $Message
|
||||||
|
)
|
||||||
|
|
||||||
|
Process {
|
||||||
|
if ( ! ( $script:Quiet ) ) {
|
||||||
|
$StageName = $( if ( $script:StageName -ne $null ) { $script:StageName } else { '' })
|
||||||
|
$Icon = ''
|
||||||
|
|
||||||
|
foreach($m in $Message) {
|
||||||
|
Write-Output " ${StageName} $($Icon.PadRight(5)) ${m}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$Columns = (Get-Host).UI.RawUI.WindowSize.Width - 5
|
103
.github/scripts/utils.pwsh/Setup-Host.ps1
vendored
Normal file
103
.github/scripts/utils.pwsh/Setup-Host.ps1
vendored
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
function Setup-Host {
|
||||||
|
if ( ! ( Test-Path function:Log-Output ) ) {
|
||||||
|
. $PSScriptRoot/Logger.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ( Test-Path function:Ensure-Location ) ) {
|
||||||
|
. $PSScriptRoot/Ensure-Location.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ( Test-Path function:Install-BuildDependencies ) ) {
|
||||||
|
. $PSScriptRoot/Install-BuildDependencies.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ( Test-Path function:Expand-ArchiveExt ) ) {
|
||||||
|
. $PSScriptRoot/Expand-ArchiveExt.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
Install-BuildDependencies -WingetFile "${ScriptHome}/.Wingetfile"
|
||||||
|
|
||||||
|
if ( $script:Target -eq '' ) { $script:Target = $script:HostArchitecture }
|
||||||
|
|
||||||
|
$script:QtVersion = $BuildSpec.platformConfig."windows-${script:Target}".qtVersion
|
||||||
|
$script:VisualStudioVersion = $BuildSpec.platformConfig."windows-${script:Target}".visualStudio
|
||||||
|
$script:PlatformSDK = $BuildSpec.platformConfig."windows-${script:Target}".platformSDK
|
||||||
|
|
||||||
|
if ( ! ( ( $script:SkipAll ) -or ( $script:SkipDeps ) ) ) {
|
||||||
|
('prebuilt', "qt${script:QtVersion}") | ForEach-Object {
|
||||||
|
$_Dependency = $_
|
||||||
|
$_Version = $BuildSpec.dependencies."${_Dependency}".version
|
||||||
|
$_BaseUrl = $BuildSpec.dependencies."${_Dependency}".baseUrl
|
||||||
|
$_Label = $BuildSpec.dependencies."${_Dependency}".label
|
||||||
|
$_Hash = $BuildSpec.dependencies."${_Dependency}".hashes."windows-${script:Target}"
|
||||||
|
|
||||||
|
if ( $BuildSpec.dependencies."${_Dependency}".PSobject.Properties.Name -contains "pdb-hashes" ) {
|
||||||
|
$_PdbHash = $BuildSpec.dependencies."${_Dependency}".'pdb-hashes'."$windows-${script:Target}"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $_Version -eq '' ) {
|
||||||
|
throw "No ${_Dependency} spec found in ${script:BuildSpecFile}."
|
||||||
|
}
|
||||||
|
|
||||||
|
Log-Information "Setting up ${_Label}..."
|
||||||
|
|
||||||
|
Push-Location -Stack BuildTemp
|
||||||
|
Ensure-Location -Path "$(Resolve-Path -Path "${ProjectRoot}/..")/obs-build-dependencies"
|
||||||
|
|
||||||
|
switch -wildcard ( $_Dependency ) {
|
||||||
|
prebuilt {
|
||||||
|
$_Filename = "windows-deps-${_Version}-${script:Target}.zip"
|
||||||
|
$_Uri = "${_BaseUrl}/${_Version}/${_Filename}"
|
||||||
|
$_Target = "plugin-deps-${_Version}-qt${script:QtVersion}-${script:Target}"
|
||||||
|
$script:DepsVersion = ${_Version}
|
||||||
|
}
|
||||||
|
"qt*" {
|
||||||
|
$_Filename = "windows-deps-qt${script:QtVersion}-${_Version}-${script:Target}.zip"
|
||||||
|
$_Uri = "${_BaseUrl}/${_Version}/${_Filename}"
|
||||||
|
$_Target = "plugin-deps-${_Version}-qt${script:QtVersion}-${script:Target}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ( Test-Path -Path $_Filename ) ) {
|
||||||
|
$Params = @{
|
||||||
|
UserAgent = 'NativeHost'
|
||||||
|
Uri = $_Uri
|
||||||
|
OutFile = $_Filename
|
||||||
|
UseBasicParsing = $true
|
||||||
|
ErrorAction = 'Stop'
|
||||||
|
}
|
||||||
|
|
||||||
|
Invoke-WebRequest @Params
|
||||||
|
Log-Status "Downloaded ${_Label} for ${script:Target}."
|
||||||
|
} else {
|
||||||
|
Log-Status "Found downloaded ${_Label}."
|
||||||
|
}
|
||||||
|
|
||||||
|
$_FileHash = Get-FileHash -Path $_Filename -Algorithm SHA256
|
||||||
|
|
||||||
|
if ( $_FileHash.Hash.ToLower() -ne $_Hash ) {
|
||||||
|
throw "Checksum of downloaded ${_Label} does not match specification. Expected '${_Hash}', 'found $(${_FileHash}.Hash.ToLower())'"
|
||||||
|
}
|
||||||
|
Log-Status "Checksum of downloaded ${_Label} matches."
|
||||||
|
|
||||||
|
if ( ! ( ( $script:SkipAll ) -or ( $script:SkipUnpack ) ) ) {
|
||||||
|
Push-Location -Stack BuildTemp
|
||||||
|
Ensure-Location -Path $_Target
|
||||||
|
|
||||||
|
Expand-ArchiveExt -Path "../${_Filename}" -DestinationPath . -Force
|
||||||
|
|
||||||
|
Pop-Location -Stack BuildTemp
|
||||||
|
}
|
||||||
|
Pop-Location -Stack BuildTemp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-HostArchitecture {
|
||||||
|
$Host64Bit = [System.Environment]::Is64BitOperatingSystem
|
||||||
|
$HostArchitecture = ('x86', 'x64')[$Host64Bit]
|
||||||
|
|
||||||
|
return $HostArchitecture
|
||||||
|
}
|
||||||
|
|
||||||
|
$script:HostArchitecture = Get-HostArchitecture
|
84
.github/scripts/utils.pwsh/Setup-Obs.ps1
vendored
Normal file
84
.github/scripts/utils.pwsh/Setup-Obs.ps1
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
function Setup-Obs {
|
||||||
|
if ( ! ( Test-Path function:Log-Output ) ) {
|
||||||
|
. $PSScriptRoot/Logger.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ( Test-Path function:Check-Git ) ) {
|
||||||
|
. $PSScriptRoot/Check-Git.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
Check-Git
|
||||||
|
|
||||||
|
if ( ! ( Test-Path function:Ensure-Location ) ) {
|
||||||
|
. $PSScriptRoot/Ensure-Location.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ( Test-Path function:Invoke-GitCheckout ) ) {
|
||||||
|
. $PSScriptRoot/Invoke-GitCheckout.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ( Test-Path function:Invoke-External ) ) {
|
||||||
|
. $PSScriptRoot/Invoke-External.ps1
|
||||||
|
}
|
||||||
|
|
||||||
|
Log-Information 'Setting up OBS Studio...'
|
||||||
|
|
||||||
|
$ObsVersion = $BuildSpec.dependencies.'obs-studio'.version
|
||||||
|
$ObsRepository = $BuildSpec.dependencies.'obs-studio'.repository
|
||||||
|
$ObsBranch = $BuildSpec.dependencies.'obs-studio'.branch
|
||||||
|
$ObsHash = $BuildSpec.dependencies.'obs-studio'.hash
|
||||||
|
|
||||||
|
if ( $ObsVersion -eq '' ) {
|
||||||
|
throw 'No obs-studio version found in buildspec.json.'
|
||||||
|
}
|
||||||
|
|
||||||
|
Push-Location -Stack BuildTemp
|
||||||
|
Ensure-Location -Path "$(Resolve-Path -Path "${ProjectRoot}/../")/obs-studio"
|
||||||
|
|
||||||
|
if ( ! ( ( $script:SkipAll ) -or ( $script:SkipUnpack ) ) ) {
|
||||||
|
Invoke-GitCheckout -Uri $ObsRepository -Commit $ObsHash -Path . -Branch $ObsBranch
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! ( ( $script:SkipAll ) -or ( $script:SkipBuild ) ) ) {
|
||||||
|
Log-Information 'Configuring OBS Studio...'
|
||||||
|
|
||||||
|
$NumProcessors = (Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors
|
||||||
|
|
||||||
|
if ( $NumProcessors -gt 1 ) {
|
||||||
|
$env:UseMultiToolTask = $true
|
||||||
|
$env:EnforceProcessCountAcrossBuilds = $true
|
||||||
|
}
|
||||||
|
|
||||||
|
$DepsPath = "plugin-deps-${script:DepsVersion}-qt${script:QtVersion}-${script:Target}"
|
||||||
|
|
||||||
|
$CmakeArgs = @(
|
||||||
|
'-G', $script:CmakeGenerator
|
||||||
|
"-DCMAKE_SYSTEM_VERSION=${script:PlatformSDK}"
|
||||||
|
"-DCMAKE_GENERATOR_PLATFORM=$(if (${script:Target} -eq "x86") { "Win32" } else { "x64" })"
|
||||||
|
"-DCMAKE_BUILD_TYPE=${script:Configuration}"
|
||||||
|
"-DQT_VERSION=${script:QtVersion}"
|
||||||
|
'-DENABLE_PLUGINS=OFF'
|
||||||
|
'-DENABLE_UI=OFF'
|
||||||
|
'-DENABLE_SCRIPTING=OFF'
|
||||||
|
"-DCMAKE_INSTALL_PREFIX:PATH=$(Resolve-Path -Path "${ProjectRoot}/../obs-build-dependencies/${DepsPath}")"
|
||||||
|
"-DCMAKE_PREFIX_PATH:PATH=$(Resolve-Path -Path "${ProjectRoot}/../obs-build-dependencies/${DepsPath}")"
|
||||||
|
)
|
||||||
|
|
||||||
|
Log-Debug "Attempting to configure OBS with CMake arguments: $($CmakeArgs | Out-String)"
|
||||||
|
Log-Information "Configuring OBS..."
|
||||||
|
Invoke-External cmake -S . -B plugin_build_${script:Target} @CmakeArgs
|
||||||
|
|
||||||
|
Log-Information 'Building libobs and obs-frontend-api...'
|
||||||
|
$CmakeArgs = @(
|
||||||
|
'--config', "$( if ( $script:Configuration -eq '' ) { 'RelWithDebInfo' } else { $script:Configuration })"
|
||||||
|
)
|
||||||
|
|
||||||
|
if ( $VerbosePreference -eq 'Continue' ) {
|
||||||
|
$CmakeArgs+=('--verbose')
|
||||||
|
}
|
||||||
|
|
||||||
|
Invoke-External cmake --build plugin_build_${script:Target} @CmakeArgs -t obs-frontend-api
|
||||||
|
Invoke-External cmake --install plugin_build_${script:Target} @CmakeArgs --component obs_libraries
|
||||||
|
}
|
||||||
|
Pop-Location -Stack BuildTemp
|
||||||
|
}
|
36
.github/scripts/utils.zsh/check_linux
vendored
Normal file
36
.github/scripts/utils.zsh/check_linux
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
autoload -Uz log_info log_status log_error log_debug log_warning
|
||||||
|
|
||||||
|
log_debug 'Checking for apt-get...'
|
||||||
|
if (( ! ${+commands[apt-get]} )) {
|
||||||
|
log_error 'No apt-get command found. Please install apt'
|
||||||
|
return 2
|
||||||
|
} else {
|
||||||
|
log_debug "Apt-get located at ${commands[apt-get]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
local -a dependencies=("${(f)$(<${SCRIPT_HOME}/.Aptfile)}")
|
||||||
|
local -a install_list
|
||||||
|
local binary
|
||||||
|
|
||||||
|
for dependency (${dependencies}) {
|
||||||
|
local -a tokens=(${(s: :)dependency//(,|:|\')/})
|
||||||
|
|
||||||
|
if [[ ! ${tokens[1]} == 'package' ]] continue
|
||||||
|
|
||||||
|
if [[ ${#tokens} -gt 2 && ${tokens[3]} == 'bin' ]] {
|
||||||
|
binary=${tokens[4]}
|
||||||
|
} else {
|
||||||
|
binary=${tokens[2]}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( ! ${+commands[${binary}]} )) install_list+=(${tokens[2]})
|
||||||
|
}
|
||||||
|
|
||||||
|
local -a _quiet=('' '--quiet')
|
||||||
|
|
||||||
|
log_debug "List of dependencies to install: ${install_list}"
|
||||||
|
if (( ${#install_list} )) {
|
||||||
|
if (( ! ${+CI} )) log_warning 'Dependency installation via apt may require elevated privileges'
|
||||||
|
|
||||||
|
sudo apt-get -y install ${install_list} ${_quiet[(( (_loglevel == 0) + 1 ))]}
|
||||||
|
}
|
20
.github/scripts/utils.zsh/check_macos
vendored
Normal file
20
.github/scripts/utils.zsh/check_macos
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
autoload -Uz is-at-least log_info log_error log_status read_codesign
|
||||||
|
|
||||||
|
local macos_version=$(sw_vers -productVersion)
|
||||||
|
|
||||||
|
log_info 'Checking macOS version...'
|
||||||
|
if ! is-at-least 11.0 "${macos_version}"; then
|
||||||
|
log_error "Minimum required macOS version is 11.0, but running on macOS ${macos_version}"
|
||||||
|
return 2
|
||||||
|
else
|
||||||
|
log_status "macOS ${macos_version} is recent"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info 'Checking for Homebrew...'
|
||||||
|
if (( ! ${+commands[brew]} )) {
|
||||||
|
log_error 'No Homebrew command found. Please install Homebrew (https://brew.sh)'
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
brew bundle --file "${SCRIPT_HOME}/.Brewfile"
|
||||||
|
rehash
|
52
.github/scripts/utils.zsh/check_packages
vendored
Normal file
52
.github/scripts/utils.zsh/check_packages
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
if (( ! ${+commands[packagesbuild]} )) {
|
||||||
|
autoload -Uz log_info log_status mkcd
|
||||||
|
|
||||||
|
if (( ! ${+commands[curl]} )) {
|
||||||
|
log_error 'curl not found. Please install curl.'
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( ! ${+project_root} )) {
|
||||||
|
log_error "'project_root' not set. Please set before running ${0}."
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
local -a curl_opts=()
|
||||||
|
if (( ! ${+CI} )) {
|
||||||
|
curl_opts+=(--progress-bar)
|
||||||
|
} else {
|
||||||
|
curl_opts+=(--show-error --silent)
|
||||||
|
}
|
||||||
|
curl_opts+=(--location -O ${@})
|
||||||
|
|
||||||
|
log_info 'Installing Packages.app...'
|
||||||
|
|
||||||
|
pushd
|
||||||
|
mkcd ${project_root:h}/obs-build-dependencies
|
||||||
|
|
||||||
|
local packages_url='http://s.sudre.free.fr/Software/files/Packages.dmg'
|
||||||
|
local packages_hash='6afdd25386295974dad8f078b8f1e41cabebd08e72d970bf92f707c7e48b16c9'
|
||||||
|
|
||||||
|
if [[ ! -f Packages.dmg ]] {
|
||||||
|
log_status 'Download Packages.app'
|
||||||
|
curl ${curl_opts} ${packages_url}
|
||||||
|
}
|
||||||
|
|
||||||
|
local image_checksum
|
||||||
|
read -r image_checksum _ <<< "$(sha256sum Packages.dmg)"
|
||||||
|
|
||||||
|
if [[ ${packages_hash} != ${image_checksum} ]] {
|
||||||
|
log_error "Checksum mismatch of Packages.app download.
|
||||||
|
Expected : ${packages_hash}
|
||||||
|
Actual : ${image_checksum}"
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
hdiutil attach -noverify Packages.dmg &> /dev/null && log_status 'Packages.dmg image mounted.'
|
||||||
|
|
||||||
|
log_info 'Installing Packages.app...'
|
||||||
|
packages_volume=$(hdiutil info -plist | grep '<string>/Volumes/Packages' | sed 's/.*<string>\(\/Volumes\/[^<]*\)<\/string>/\1/')
|
||||||
|
|
||||||
|
sudo installer -pkg "${packages_volume}/packages/Packages.pkg" -target / && rehash
|
||||||
|
hdiutil detach ${packages_volume} &> /dev/null && log_status 'Packages.dmg image unmounted.'
|
||||||
|
}
|
9
.github/scripts/utils.zsh/check_xcnotary
vendored
Normal file
9
.github/scripts/utils.zsh/check_xcnotary
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
autoload -Uz log_info log_error
|
||||||
|
|
||||||
|
log_info 'Checking for Homebrew...'
|
||||||
|
if (( ! ${+commands[brew]} )) {
|
||||||
|
log_error 'No Homebrew command found. Please install Homebrew (https://brew.sh)'
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( ! ${+commands[xcnotary]} )) brew install akeru-inc/tap/xcnotary
|
3
.github/scripts/utils.zsh/log_debug
vendored
Normal file
3
.github/scripts/utils.zsh/log_debug
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
if (( ! ${+_loglevel} )) typeset -g _loglevel=1
|
||||||
|
|
||||||
|
if (( _loglevel > 2 )) print -PR -e -- "%F{220}DEBUG: ${@}%f"
|
3
.github/scripts/utils.zsh/log_error
vendored
Normal file
3
.github/scripts/utils.zsh/log_error
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
local icon=' ✖︎ '
|
||||||
|
|
||||||
|
print -u2 -PR "%F{1} ${icon} %f ${@}"
|
7
.github/scripts/utils.zsh/log_info
vendored
Normal file
7
.github/scripts/utils.zsh/log_info
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
if (( ! ${+_loglevel} )) typeset -g _loglevel=1
|
||||||
|
|
||||||
|
if (( _loglevel > 0 )) {
|
||||||
|
local icon=' =>'
|
||||||
|
|
||||||
|
print -PR "%F{4} ${(r:5:)icon}%f %B${@}%b"
|
||||||
|
}
|
7
.github/scripts/utils.zsh/log_output
vendored
Normal file
7
.github/scripts/utils.zsh/log_output
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
if (( ! ${+_loglevel} )) typeset -g _loglevel=1
|
||||||
|
|
||||||
|
if (( _loglevel > 0 )) {
|
||||||
|
local icon=''
|
||||||
|
|
||||||
|
print -PR " ${(r:5:)icon} ${@}"
|
||||||
|
}
|
7
.github/scripts/utils.zsh/log_status
vendored
Normal file
7
.github/scripts/utils.zsh/log_status
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
if (( ! ${+_loglevel} )) typeset -g _loglevel=1
|
||||||
|
|
||||||
|
if (( _loglevel > 0 )) {
|
||||||
|
local icon=' >'
|
||||||
|
|
||||||
|
print -PR "%F{2} ${(r:5:)icon}%f ${@}"
|
||||||
|
}
|
5
.github/scripts/utils.zsh/log_warning
vendored
Normal file
5
.github/scripts/utils.zsh/log_warning
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
if (( _loglevel > 0 )) {
|
||||||
|
local icon=' =>'
|
||||||
|
|
||||||
|
print -PR "%F{3} ${(r:5:)icon} ${@}%f"
|
||||||
|
}
|
1
.github/scripts/utils.zsh/mkcd
vendored
Normal file
1
.github/scripts/utils.zsh/mkcd
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[[ -n ${1} ]] && mkdir -p ${1} && builtin cd ${1}
|
7
.github/scripts/utils.zsh/read_codesign
vendored
Normal file
7
.github/scripts/utils.zsh/read_codesign
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
autoload -Uz log_info
|
||||||
|
|
||||||
|
if (( ! ${+CODESIGN_IDENT} )) {
|
||||||
|
typeset -g CODESIGN_IDENT
|
||||||
|
log_info 'Setting up identity for application codesigning...'
|
||||||
|
read CODESIGN_IDENT'?Apple Developer Application ID: '
|
||||||
|
}
|
7
.github/scripts/utils.zsh/read_codesign_installer
vendored
Normal file
7
.github/scripts/utils.zsh/read_codesign_installer
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
autoload -Uz log_info
|
||||||
|
|
||||||
|
if (( ! ${+CODESIGN_IDENT_INSTALLER} )) {
|
||||||
|
typeset -g CODESIGN_IDENT_INSTALLER
|
||||||
|
log_info 'Setting up identity for installer package codesigning...'
|
||||||
|
read CODESIGN_IDENT_INSTALLER'?Apple Developer Installer ID: '
|
||||||
|
}
|
33
.github/scripts/utils.zsh/read_codesign_pass
vendored
Normal file
33
.github/scripts/utils.zsh/read_codesign_pass
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
##############################################################################
|
||||||
|
# Apple Developer credentials necessary:
|
||||||
|
#
|
||||||
|
# + Signing for distribution and notarization require an active Apple
|
||||||
|
# Developer membership
|
||||||
|
# + An Apple Development identity is needed for code signing
|
||||||
|
# (i.e. 'Apple Development: YOUR APPLE ID (PROVIDER)')
|
||||||
|
# + Your Apple developer ID is needed for notarization
|
||||||
|
# + An app-specific password is necessary for notarization from CLI
|
||||||
|
# + This password will be stored in your macOS keychain under the identifier
|
||||||
|
# 'OBS-Codesign-Password'with access Apple's 'altool' only.
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
autoload -Uz read_codesign read_codesign_user log_info
|
||||||
|
|
||||||
|
if (( ! ${+CODESIGN_IDENT} )) {
|
||||||
|
read_codesign
|
||||||
|
}
|
||||||
|
|
||||||
|
local codesign_ident_short=$(print "${CODESIGN_IDENT}" | /usr/bin/sed -En 's/.+\((.+)\)/\1/p')
|
||||||
|
|
||||||
|
if (( ! ${+CODESIGN_IDENT_USER} )) {
|
||||||
|
read_codesign_user
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info 'Setting up password for notarization keychain...'
|
||||||
|
if (( ! ${+CODESIGN_IDENT_PASS} )) {
|
||||||
|
read -s CODESIGN_IDENT_PASS'?Apple Developer ID password: '
|
||||||
|
}
|
||||||
|
|
||||||
|
print ''
|
||||||
|
log_info 'Setting up notarization keychain...'
|
||||||
|
xcrun notarytool store-credentials 'OBS-Codesign-Password' --apple-id "${CODESIGN_IDENT_USER}" --team-id "${codesign_ident_short}" --password "${CODESIGN_IDENT_PASS}"
|
7
.github/scripts/utils.zsh/read_codesign_user
vendored
Normal file
7
.github/scripts/utils.zsh/read_codesign_user
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
autoload -Uz log_info
|
||||||
|
|
||||||
|
if (( ! ${+CODESIGN_IDENT_USER} )) {
|
||||||
|
typeset -g CODESIGN_IDENT_USER
|
||||||
|
log_info 'Setting up developer id for codesigning...'
|
||||||
|
read CODESIGN_IDENT_USER'?Apple Developer ID: '
|
||||||
|
}
|
17
.github/scripts/utils.zsh/set_loglevel
vendored
Normal file
17
.github/scripts/utils.zsh/set_loglevel
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
autoload -Uz log_debug log_error
|
||||||
|
|
||||||
|
local -r _usage="Usage: %B${0}%b <loglevel>
|
||||||
|
|
||||||
|
Set log level, following levels are supported: 0 (quiet), 1 (normal), 2 (verbose), 3 (debug)"
|
||||||
|
|
||||||
|
if (( ! # )); then
|
||||||
|
log_error 'Called without arguments.'
|
||||||
|
log_output ${_usage}
|
||||||
|
return 2
|
||||||
|
elif (( ${1} >= 4 )); then
|
||||||
|
log_error 'Called with loglevel > 3.'
|
||||||
|
log_output ${_usage}
|
||||||
|
fi
|
||||||
|
|
||||||
|
typeset -g -i -r _loglevel=${1}
|
||||||
|
log_debug "Log level set to '${1}'"
|
14
.github/scripts/utils.zsh/setup_ccache
vendored
Normal file
14
.github/scripts/utils.zsh/setup_ccache
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
autoload -Uz log_debug log_warning
|
||||||
|
|
||||||
|
if (( ${+commands[ccache]} )) {
|
||||||
|
log_debug "Found ccache at ${commands[ccache]}"
|
||||||
|
|
||||||
|
if (( ${+CI} )) {
|
||||||
|
ccache --set-config=cache_dir="${GITHUB_WORKSPACE:-${HOME}}/.ccache"
|
||||||
|
ccache --set-config=max_size="${CCACHE_SIZE:-500M}"
|
||||||
|
ccache --set-config=compression=true
|
||||||
|
ccache -z > /dev/null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log_warning "No ccache found on the system"
|
||||||
|
}
|
62
.github/scripts/utils.zsh/setup_linux
vendored
Normal file
62
.github/scripts/utils.zsh/setup_linux
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
autoload -Uz log_error log_status log_info mkcd
|
||||||
|
|
||||||
|
if (( ! ${+project_root} )) {
|
||||||
|
log_error "'project_root' not set. Please set before running ${0}."
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( ! ${+target} )) {
|
||||||
|
log_error "'target' not set. Please set before running ${0}."
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
pushd ${project_root}
|
||||||
|
|
||||||
|
typeset -g QT_VERSION
|
||||||
|
read -r QT_VERSION <<< \
|
||||||
|
"$(jq -r --arg target "${target}" \
|
||||||
|
'.platformConfig[$target] | { qtVersion } | join(" ")' \
|
||||||
|
${project_root}/buildspec.json)"
|
||||||
|
|
||||||
|
if (( ! (${skips[(Ie)all]} + ${skips[(Ie)deps]}) )) {
|
||||||
|
log_info 'Installing obs build dependencies...'
|
||||||
|
|
||||||
|
sudo apt-get install -y \
|
||||||
|
build-essential \
|
||||||
|
libcurl4-openssl-dev \
|
||||||
|
libavcodec-dev libavdevice-dev libavfilter-dev libavformat-dev libavutil-dev \
|
||||||
|
libswresample-dev libswscale-dev \
|
||||||
|
libjansson-dev \
|
||||||
|
libx11-xcb-dev \
|
||||||
|
libgles2-mesa-dev \
|
||||||
|
libwayland-dev \
|
||||||
|
libpulse-dev
|
||||||
|
|
||||||
|
local -a _qt_packages=()
|
||||||
|
|
||||||
|
if (( QT_VERSION == 5 )) {
|
||||||
|
_qt_packages+=(
|
||||||
|
qtbase5-dev
|
||||||
|
libqt5svg5-dev
|
||||||
|
qtbase5-private-dev
|
||||||
|
libqt5x11extras5-dev
|
||||||
|
)
|
||||||
|
} elif (( QT_VERSION == 6 )) {
|
||||||
|
_qt_packages+=(
|
||||||
|
qt6-base-dev
|
||||||
|
libqt6svg6-dev
|
||||||
|
qt6-base-private-dev
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
log_error "Unsupported Qt version '${QT_VERSION}' specified."
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
sudo apt-get install -y ${_qt_packages}
|
||||||
|
}
|
||||||
|
|
||||||
|
local deps_version
|
||||||
|
read -r deps_version <<< \
|
||||||
|
"$(jq -r '.dependencies.prebuilt.version' ${buildspec_file})"
|
||||||
|
|
||||||
|
typeset -g OBS_DEPS_VERSION=${deps_version}
|
127
.github/scripts/utils.zsh/setup_macos
vendored
Normal file
127
.github/scripts/utils.zsh/setup_macos
vendored
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
autoload -Uz log_error log_status log_info mkcd
|
||||||
|
|
||||||
|
if (( ! ${+commands[curl]} )) {
|
||||||
|
log_error 'curl not found. Please install curl.'
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( ! ${+commands[jq]} )) {
|
||||||
|
log_error 'jq not found. Please install jq.'
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( ! ${+project_root} )) {
|
||||||
|
log_error "'project_root' not set. Please set before running ${0}."
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( ! ${+target} )) {
|
||||||
|
log_error "'target' not set. Please set before running ${0}."
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
local -a curl_opts=()
|
||||||
|
if (( ! ${+CI} )) {
|
||||||
|
curl_opts+=(--progress-bar)
|
||||||
|
} else {
|
||||||
|
curl_opts+=(--show-error --silent)
|
||||||
|
}
|
||||||
|
curl_opts+=(--location -O ${@})
|
||||||
|
|
||||||
|
pushd ${project_root}
|
||||||
|
|
||||||
|
local _qt_version
|
||||||
|
local _deployment_target
|
||||||
|
read -r _qt_version _deployment_target <<< \
|
||||||
|
"$(jq -r --arg target "${target}" \
|
||||||
|
'.platformConfig[$target] | { qtVersion, deploymentTarget } | join (" ")' \
|
||||||
|
${buildspec_file})"
|
||||||
|
|
||||||
|
typeset -g QT_VERSION=${_qt_version}
|
||||||
|
typeset -g DEPLOYMENT_TARGET=${_deployment_target}
|
||||||
|
|
||||||
|
if (( ! (${skips[(Ie)all]} + ${skips[(Ie)deps]}) )) {
|
||||||
|
mkdir -p ${project_root:h}/obs-build-dependencies
|
||||||
|
|
||||||
|
local dependency
|
||||||
|
local deps_version
|
||||||
|
local deps_baseurl
|
||||||
|
local deps_label
|
||||||
|
local deps_hash
|
||||||
|
local _filename
|
||||||
|
local _url
|
||||||
|
local _target
|
||||||
|
local artifact_checksum
|
||||||
|
|
||||||
|
for dependency ('prebuilt' "qt${QT_VERSION}") {
|
||||||
|
IFS=';' read -r deps_version deps_baseurl deps_label deps_hash <<< \
|
||||||
|
"$(jq -r --arg dependency "${dependency}" --arg target "${target}" \
|
||||||
|
'.dependencies[$dependency] | {version, baseUrl, "label", "hash": .hashes[$target]} | join(";")' \
|
||||||
|
${buildspec_file})"
|
||||||
|
|
||||||
|
if [[ -z "${deps_version}" ]] {
|
||||||
|
log_error "No ${dependency} spec found in ${buildspec_file}."
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
log_info "Setting up ${deps_label}..."
|
||||||
|
|
||||||
|
pushd ${project_root:h}/obs-build-dependencies
|
||||||
|
|
||||||
|
case ${dependency} {
|
||||||
|
prebuilt)
|
||||||
|
_filename="macos-deps-${deps_version}-${target##*-}.tar.xz"
|
||||||
|
_url="${deps_baseurl}/${deps_version}/${_filename}"
|
||||||
|
_target="plugin-deps-${deps_version}-qt${QT_VERSION}-${target##*-}"
|
||||||
|
typeset -g OBS_DEPS_VERSION=${deps_version}
|
||||||
|
;;
|
||||||
|
qt*)
|
||||||
|
if (( ${+CI} )) {
|
||||||
|
_filename="macos-deps-qt${QT_VERSION}-${deps_version}-universal.tar.xz"
|
||||||
|
deps_hash="$(jq -r --arg dependency "${dependency}" \
|
||||||
|
'.dependencies[$dependency].hashes["macos-universal"]' \
|
||||||
|
${buildspec_file})"
|
||||||
|
} else {
|
||||||
|
_filename="macos-deps-qt${QT_VERSION}-${deps_version}-${target##*-}.tar.xz"
|
||||||
|
}
|
||||||
|
_url="${deps_baseurl}/${deps_version}/${_filename}"
|
||||||
|
_target="plugin-deps-${deps_version}-qt${QT_VERSION}-${target##*-}"
|
||||||
|
;;
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ ! -f ${_filename} ]] {
|
||||||
|
log_debug "Running curl ${curl_opts} ${_url}"
|
||||||
|
curl ${curl_opts} ${_url} && \
|
||||||
|
log_status "Downloaded ${deps_label} for ${target}."
|
||||||
|
} else {
|
||||||
|
log_status "Found downloaded ${deps_label}"
|
||||||
|
}
|
||||||
|
|
||||||
|
read -r artifact_checksum _ <<< "$(sha256sum ${_filename})"
|
||||||
|
if [[ ${deps_hash} != ${artifact_checksum} ]] {
|
||||||
|
log_error "Checksum of downloaded ${deps_label} does not match specification.
|
||||||
|
Expected : ${deps_hash}
|
||||||
|
Actual : ${artifact_checksum}"
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
log_status "Checksum of downloaded ${deps_label} matches."
|
||||||
|
|
||||||
|
if (( ! (${skips[(Ie)all]} + ${skips[(Ie)unpack]}) )) {
|
||||||
|
mkdir -p ${_target} && pushd ${_target}
|
||||||
|
|
||||||
|
XZ_OPT=-T0 tar -xzf ../${_filename} && log_status "${deps_label} extracted."
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
popd
|
||||||
|
pushd ${project_root:h}/obs-build-dependencies
|
||||||
|
xattr -r -d com.apple.quarantine *
|
||||||
|
log_status 'Removed quarantine flag from downloaded dependencies...'
|
||||||
|
popd
|
||||||
|
} else {
|
||||||
|
local deps_version
|
||||||
|
read -r deps_version <<< \
|
||||||
|
"$(jq -r '.dependencies.prebuilt.version' ${buildspec_file})"
|
||||||
|
|
||||||
|
typeset -g OBS_DEPS_VERSION=${deps_version}
|
||||||
|
}
|
122
.github/scripts/utils.zsh/setup_obs
vendored
Normal file
122
.github/scripts/utils.zsh/setup_obs
vendored
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
autoload -Uz log_error log_info log_status
|
||||||
|
|
||||||
|
if (( ! ${+buildspec_file} )) {
|
||||||
|
log_error "'buildspec_file' not set. Please set before running ${0}."
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( ! ${+commands[git]} )) {
|
||||||
|
log_error 'git not found. Please install git.'
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( ! ${+commands[jq]} )) {
|
||||||
|
log_error 'jq not found. Please install jq.'
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( ! ${+project_root} )) {
|
||||||
|
log_error "'project_root' not set. Please set before running ${0}."
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( ! ${+target} )) {
|
||||||
|
log_error "'target' not set. Please set before running ${0}."
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info 'Setting up OBS-Studio...'
|
||||||
|
|
||||||
|
local obs_version
|
||||||
|
local obs_repo
|
||||||
|
local obs_branch
|
||||||
|
local obs_hash
|
||||||
|
|
||||||
|
read -r obs_version obs_repo obs_branch obs_hash <<< \
|
||||||
|
"$(jq -r --arg key "obs-studio" \
|
||||||
|
'.dependencies[$key] | {version, repository, branch, hash} | join(" ")' \
|
||||||
|
${buildspec_file})"
|
||||||
|
|
||||||
|
if [[ -z ${obs_version} ]] {
|
||||||
|
log_error "No obs-studio version found in buildspec.json"
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
pushd
|
||||||
|
mkcd ${project_root:h}/obs-studio
|
||||||
|
|
||||||
|
if (( ! (${skips[(Ie)all]} + ${skips[(Ie)unpack]}) )) {
|
||||||
|
if [[ -d .git ]] {
|
||||||
|
git config advice.detachedHead false
|
||||||
|
git config remote.pluginbuild.url "${obs_repo:-https://github.com/obsproject/obs-studio.git}"
|
||||||
|
git config remote.pluginbuild.fetch "+refs/heads/${obs_branch:-master}:refs/remotes/origin/${obs_branch:-master}"
|
||||||
|
|
||||||
|
git rev-parse -q --verify "${obs_hash}^{commit}" > /dev/null || git fetch pluginbuild
|
||||||
|
git checkout ${obs_branch:-master} -B ${product_name}
|
||||||
|
git reset --hard "${obs_hash}"
|
||||||
|
log_status 'Found existing obs-studio repository.'
|
||||||
|
} else {
|
||||||
|
git clone "${obs_repo:-https://github.com/obsproject/obs-studio.git}" "${PWD}"
|
||||||
|
git config advice.detachedHead false
|
||||||
|
git checkout -f "${obs_hash}" --
|
||||||
|
git checkout ${obs_branch:-master} -b ${product_name}
|
||||||
|
log_status 'obs-studio checked out.'
|
||||||
|
}
|
||||||
|
|
||||||
|
git submodule foreach --recursive git submodule sync
|
||||||
|
git submodule update --init --recursive
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( ! (${skips[(Ie)all]} + ${skips[(Ie)build]}) )) {
|
||||||
|
log_info 'Configuring obs-studio...'
|
||||||
|
|
||||||
|
local -a cmake_args=(
|
||||||
|
-DCMAKE_BUILD_TYPE=${BUILD_CONFIG:-Release}
|
||||||
|
-DQT_VERSION=${QT_VERSION}
|
||||||
|
-DENABLE_PLUGINS=OFF
|
||||||
|
-DENABLE_UI=OFF
|
||||||
|
-DENABLE_SCRIPTING=OFF
|
||||||
|
-DCMAKE_INSTALL_PREFIX="${project_root:h}/obs-build-dependencies/plugin-deps-${OBS_DEPS_VERSION}-qt${QT_VERSION}-${target##*-}"
|
||||||
|
-DCMAKE_PREFIX_PATH="${project_root:h}/obs-build-dependencies/plugin-deps-${OBS_DEPS_VERSION}-qt${QT_VERSION}-${target##*-}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (( _loglevel == 0 )) cmake_args+=(-Wno_deprecated -Wno-dev --log-level=ERROR)
|
||||||
|
if (( _loglevel > 2 )) cmake_args+=(--debug-output)
|
||||||
|
|
||||||
|
local num_procs
|
||||||
|
|
||||||
|
case ${target} {
|
||||||
|
macos-*)
|
||||||
|
autoload -Uz read_codesign
|
||||||
|
if (( ${+CODESIGN} )) {
|
||||||
|
read_codesign
|
||||||
|
}
|
||||||
|
|
||||||
|
cmake_args+=(
|
||||||
|
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
|
||||||
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||||
|
-DOBS_CODESIGN_LINKER=ON
|
||||||
|
-DOBS_BUNDLE_CODESIGN_IDENTITY="${CODESIGN_IDENT:--}"
|
||||||
|
)
|
||||||
|
num_procs=$(( $(sysctl -n hw.ncpu) + 1 ))
|
||||||
|
;;
|
||||||
|
linux-*)
|
||||||
|
cmake_args+=(
|
||||||
|
-DENABLE_PIPEWIRE=OFF
|
||||||
|
)
|
||||||
|
num_procs=$(( $(nproc) + 1 ))
|
||||||
|
;;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug "Attempting to configure OBS with CMake arguments: ${cmake_args}"
|
||||||
|
cmake -S . -B plugin_build_${target##*-} -G ${generator} ${cmake_args}
|
||||||
|
|
||||||
|
log_info 'Building libobs and obs-frontend-api...'
|
||||||
|
local -a cmake_args=()
|
||||||
|
if (( _loglevel > 1 )) cmake_args+=(--verbose)
|
||||||
|
if [[ ${generator} == 'Unix Makefiles' ]] cmake_args+=(--parallel ${num_procs})
|
||||||
|
cmake --build plugin_build_${target##*-} --config ${BUILD_CONFIG:-Release} ${cmake_args} -t obs-frontend-api
|
||||||
|
cmake --install plugin_build_${target##*-} --config ${BUILD_CONFIG:-Release} --component obs_libraries ${cmake_args}
|
||||||
|
}
|
||||||
|
|
||||||
|
popd
|
386
.github/workflows/main.yml
vendored
Normal file
386
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
name: Plugin Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
branches:
|
||||||
|
- 4.x-compat-new-cmake
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
branches:
|
||||||
|
- 4.x-compat-new-cmake
|
||||||
|
|
||||||
|
env:
|
||||||
|
PLUGIN_NAME: 'obs-websocket-compat'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
clang_check:
|
||||||
|
name: 01 - Code Format Check
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install clang-format
|
||||||
|
run: sudo apt-get install -y clang-format-13
|
||||||
|
|
||||||
|
- name: Run clang-format
|
||||||
|
run: ./.github/scripts/check-format.sh && ./.github/scripts/check-changes.sh
|
||||||
|
|
||||||
|
- name: Install cmake-format
|
||||||
|
run: sudo pip install cmakelang
|
||||||
|
|
||||||
|
- name: Run cmake-format
|
||||||
|
run: ./.github/scripts/check-cmake.sh
|
||||||
|
|
||||||
|
macos_build:
|
||||||
|
name: 02 - macOS
|
||||||
|
runs-on: macos-12
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
arch: [x86_64, arm64, universal]
|
||||||
|
if: always()
|
||||||
|
needs: [clang_check]
|
||||||
|
outputs:
|
||||||
|
commitHash: ${{ steps.setup.outputs.commitHash }}
|
||||||
|
env:
|
||||||
|
CODESIGN_IDENT: '-'
|
||||||
|
CODESIGN_IDENT_INSTALLER: ''
|
||||||
|
MACOSX_DEPLOYMENT_TARGET: '10.15'
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: zsh {0}
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
path: plugin
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Checkout obs-studio
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: 'obsproject/obs-studio'
|
||||||
|
path: obs-studio
|
||||||
|
fetch-depth: 0
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup Environment
|
||||||
|
id: setup
|
||||||
|
working-directory: ${{ github.workspace }}/plugin
|
||||||
|
run: |
|
||||||
|
## SETUP ENVIRONMENT SCRIPT
|
||||||
|
print '::group::Clean Homebrew Environment'
|
||||||
|
typeset -a to_remove=()
|
||||||
|
|
||||||
|
for formula (speexdsp curl php) {
|
||||||
|
if [[ -d ${HOMEBREW_PREFIX}/opt/${formula} ]] to_remove+=(${formula})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( #to_remove > 0 )) brew uninstall --ignore-dependencies ${to_remove}
|
||||||
|
print '::endgroup::'
|
||||||
|
|
||||||
|
print '::group::Set up code signing'
|
||||||
|
if [[ '${{ secrets.MACOS_SIGNING_APPLICATION_IDENTITY }}' != '' && \
|
||||||
|
'${{ secrets.MACOS_INSTALLER_IDENTITY }}' != '' && \
|
||||||
|
'${{ secrets.MACOS_SIGNING_CERT }}' != '' ]] {
|
||||||
|
print '::set-output name=haveCodesignIdent::true'
|
||||||
|
} else {
|
||||||
|
print '::set-output name=haveCodesignIdent::false'
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ '${{ secrets.MACOS_NOTARIZATION_USERNAME }}' != '' && \
|
||||||
|
'${{ secrets.MACOS_NOTARIZATION_PASSWORD }}' != '' ]] {
|
||||||
|
print '::set-output name=haveNotarizationUser::true'
|
||||||
|
} else {
|
||||||
|
print '::set-output name=haveNotarizationUser::false'
|
||||||
|
}
|
||||||
|
print '::endgroup::'
|
||||||
|
|
||||||
|
print "::set-output name=ccacheDate::$(date +"%Y-%m-%d")"
|
||||||
|
print "::set-output name=commitHash::${"$(git rev-parse HEAD)"[0,9]}"
|
||||||
|
|
||||||
|
- name: Restore Compilation Cache
|
||||||
|
id: ccache-cache
|
||||||
|
uses: actions/cache@v2.1.7
|
||||||
|
with:
|
||||||
|
path: ${{ github.workspace }}/.ccache
|
||||||
|
key: macos-${{ matrix.arch }}-ccache-plugin-${{ steps.setup.outputs.ccacheDate }}
|
||||||
|
restore-keys: |
|
||||||
|
macos-${{ matrix.arch }}-ccache-plugin-
|
||||||
|
|
||||||
|
- name: Check for GitHub Labels
|
||||||
|
id: seekingTesters
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
run: |
|
||||||
|
if [[ -n "$(curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" -s "${{ github.event.pull_request.url }}" | jq -e '.labels[] | select(.name == "Seeking Testers")')" ]] {
|
||||||
|
print '::set-output name=found::true'
|
||||||
|
} else {
|
||||||
|
print '::set-output name=found::false'
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Install Apple Developer Certificate
|
||||||
|
if: ${{ github.event_name != 'pull_request' && steps.setup.outputs.haveCodesignIdent == 'true' }}
|
||||||
|
uses: apple-actions/import-codesign-certs@253ddeeac23f2bdad1646faac5c8c2832e800071
|
||||||
|
with:
|
||||||
|
keychain-password: ${{ github.run_id }}
|
||||||
|
p12-file-base64: ${{ secrets.MACOS_SIGNING_CERT }}
|
||||||
|
p12-password: ${{ secrets.MACOS_SIGNING_CERT_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Set Signing Identity
|
||||||
|
if: ${{ github.event_name != 'pull_request' && steps.setup.outputs.haveCodesignIdent == 'true' }}
|
||||||
|
run: |
|
||||||
|
print "CODESIGN_IDENT=${{ secrets.MACOS_SIGNING_APPLICATION_IDENTITY }}" >> $GITHUB_ENV
|
||||||
|
print "CODESIGN_IDENT_INSTALLER=${{ secrets.MACOS_INSTALLER_IDENTITY }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build Plugin
|
||||||
|
uses: ./plugin/.github/actions/build-plugin
|
||||||
|
with:
|
||||||
|
workingDirectory: ${{ github.workspace }}/plugin
|
||||||
|
target: ${{ matrix.arch }}
|
||||||
|
config: RelWithDebInfo
|
||||||
|
codesign: 'true'
|
||||||
|
codesignIdent: ${{ env.CODESIGN_IDENT }}
|
||||||
|
|
||||||
|
- name: Package Plugin
|
||||||
|
uses: ./plugin/.github/actions/package-plugin
|
||||||
|
with:
|
||||||
|
workingDirectory: ${{ github.workspace }}/plugin
|
||||||
|
target: ${{ matrix.arch }}
|
||||||
|
config: RelWithDebInfo
|
||||||
|
codesign: ${{ github.event_name != 'pull_request' && steps.setup.outputs.haveCodesignIdent == 'true' }}
|
||||||
|
notarize: ${{ startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request' && steps.setup.outputs.haveNotarizationUser == 'true' }}
|
||||||
|
codesignIdent: ${{ env.CODESIGN_IDENT }}
|
||||||
|
installerIdent: ${{ env.CODESIGN_IDENT_INSTALLER }}
|
||||||
|
codesignUser: ${{ secrets.MACOS_NOTARIZATION_USERNAME }}
|
||||||
|
codesignPass: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Upload Build Artifact
|
||||||
|
if: ${{ success() && (github.event_name != 'pull_request' || steps.seekingTesters.outputs.found == 'true') }}
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ env.PLUGIN_NAME }}-macos-${{ matrix.arch }}-${{ steps.setup.outputs.commitHash }}
|
||||||
|
path: ${{ github.workspace }}/plugin/release/${{ env.PLUGIN_NAME }}-*-macos-${{ matrix.arch }}.pkg
|
||||||
|
|
||||||
|
linux_build:
|
||||||
|
name: 02 - Linux
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
arch: [x86_64]
|
||||||
|
if: always()
|
||||||
|
needs: [clang_check]
|
||||||
|
outputs:
|
||||||
|
commitHash: ${{ steps.setup.outputs.commitHash }}
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
path: plugin
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Checkout obs-studio
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: 'obsproject/obs-studio'
|
||||||
|
path: obs-studio
|
||||||
|
fetch-depth: 0
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup Environment
|
||||||
|
working-directory: ${{ github.workspace }}/plugin
|
||||||
|
id: setup
|
||||||
|
run: |
|
||||||
|
## SETUP ENVIRONMENT SCRIPT
|
||||||
|
echo "::set-output name=ccacheDate::$(date +"%Y-%m-%d")"
|
||||||
|
echo "::set-output name=commitHash::$(git rev-parse HEAD | cut -c1-9)"
|
||||||
|
|
||||||
|
- name: Restore Compilation Cache
|
||||||
|
id: ccache-cache
|
||||||
|
uses: actions/cache@v2.1.7
|
||||||
|
with:
|
||||||
|
path: ${{ github.workspace }}/.ccache
|
||||||
|
key: linux-${{ matrix.arch }}-ccache-plugin-${{ steps.setup.outputs.ccacheDate }}
|
||||||
|
restore-keys: |
|
||||||
|
linux-${{ matrix.arch }}-ccache-plugin-
|
||||||
|
|
||||||
|
- name: Check for GitHub Labels
|
||||||
|
id: seekingTesters
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
run: |
|
||||||
|
## GITHUB LABEL SCRIPT
|
||||||
|
if [[ -n "$(curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" -s "${{ github.event.pull_request.url }}" | jq -e '.labels[] | select(.name == "Seeking Testers")')" ]]; then
|
||||||
|
echo '::set-output name=found::true'
|
||||||
|
else
|
||||||
|
echo '::set-output name=found::false'
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build Plugin
|
||||||
|
uses: ./plugin/.github/actions/build-plugin
|
||||||
|
with:
|
||||||
|
workingDirectory: ${{ github.workspace }}/plugin
|
||||||
|
target: ${{ matrix.arch }}
|
||||||
|
config: RelWithDebInfo
|
||||||
|
|
||||||
|
- name: Package Plugin
|
||||||
|
uses: ./plugin/.github/actions/package-plugin
|
||||||
|
with:
|
||||||
|
workingDirectory: ${{ github.workspace }}/plugin
|
||||||
|
target: ${{ matrix.arch }}
|
||||||
|
config: RelWithDebInfo
|
||||||
|
|
||||||
|
- name: Upload Build Artifact
|
||||||
|
if: ${{ success() && (github.event_name != 'pull_request' || steps.seekingTesters.outputs.found == 'true') }}
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ env.PLUGIN_NAME }}-linux-${{ matrix.arch }}-${{ steps.setup.outputs.commitHash }}
|
||||||
|
path: ${{ github.workspace }}/plugin/release/${{ env.PLUGIN_NAME }}-*-linux-${{ matrix.arch }}.*
|
||||||
|
|
||||||
|
windows_build:
|
||||||
|
name: 02 - Windows
|
||||||
|
runs-on: windows-2022
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
arch: [x86, x64]
|
||||||
|
if: always()
|
||||||
|
needs: [clang_check]
|
||||||
|
outputs:
|
||||||
|
commitHash: ${{ steps.setup.outputs.commitHash }}
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: pwsh
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
path: plugin
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Checkout obs-studio
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: 'obsproject/obs-studio'
|
||||||
|
path: obs-studio
|
||||||
|
fetch-depth: 0
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup Environment
|
||||||
|
working-directory: ${{ github.workspace }}/plugin
|
||||||
|
id: setup
|
||||||
|
run: |
|
||||||
|
## SETUP ENVIRONMENT SCRIPT
|
||||||
|
$CommitHash = (git rev-parse HEAD)[0..8] -join ''
|
||||||
|
Write-Output "::set-output name=commitHash::${CommitHash}"
|
||||||
|
|
||||||
|
- name: Check for GitHub Labels
|
||||||
|
id: seekingTesters
|
||||||
|
working-directory: ${{ github.workspace }}/plugin
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
run: |
|
||||||
|
## GITHUB LABEL SCRIPT
|
||||||
|
$LabelFound = try {
|
||||||
|
$Params = @{
|
||||||
|
Authentication = 'Bearer'
|
||||||
|
Token = (ConvertTo-SecureString '${{ secrets.GITHUB_TOKEN }}' -AsPlainText)
|
||||||
|
Uri = '${{ github.event.pull_request.url }}'
|
||||||
|
UseBasicParsing = $true
|
||||||
|
}
|
||||||
|
|
||||||
|
(Invoke-RestMethod @Params).labels.name.contains('Seeking Testers')
|
||||||
|
} catch {
|
||||||
|
$false
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "::set-output name=found::$(([string]${LabelFound}).ToLower())"
|
||||||
|
|
||||||
|
- name: Build Plugin
|
||||||
|
uses: ./plugin/.github/actions/build-plugin
|
||||||
|
with:
|
||||||
|
workingDirectory: ${{ github.workspace }}/plugin
|
||||||
|
target: ${{ matrix.arch }}
|
||||||
|
config: RelWithDebInfo
|
||||||
|
visualStudio: 'Visual Studio 17 2022'
|
||||||
|
|
||||||
|
- name: Package Plugin
|
||||||
|
uses: ./plugin/.github/actions/package-plugin
|
||||||
|
with:
|
||||||
|
workingDirectory: ${{ github.workspace }}/plugin
|
||||||
|
target: ${{ matrix.arch }}
|
||||||
|
config: RelWithDebInfo
|
||||||
|
|
||||||
|
- name: Upload Build Artifact
|
||||||
|
if: ${{ success() && (github.event_name != 'pull_request' || steps.seekingTesters.outputs.found == 'true') }}
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ env.PLUGIN_NAME }}-windows-${{ matrix.arch }}-${{ steps.setup.outputs.commitHash }}
|
||||||
|
path: ${{ github.workspace }}/plugin/release/${{ env.PLUGIN_NAME }}-*.zip
|
||||||
|
|
||||||
|
- name: Package Plugin Installer
|
||||||
|
if: ${{ startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request' }}
|
||||||
|
uses: ./plugin/.github/actions/package-plugin
|
||||||
|
with:
|
||||||
|
workingDirectory: ${{ github.workspace }}/plugin
|
||||||
|
target: ${{ matrix.arch }}
|
||||||
|
config: RelWithDebInfo
|
||||||
|
createInstaller: true
|
||||||
|
|
||||||
|
- name: Upload Installer Artifact
|
||||||
|
if: ${{ startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request' }}
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ env.PLUGIN_NAME }}-windows-${{ matrix.arch }}-${{ steps.setup.outputs.commitHash }}-installer
|
||||||
|
path: ${{ github.workspace }}/plugin/release/${{ env.PLUGIN_NAME }}-*.exe
|
||||||
|
|
||||||
|
make-release:
|
||||||
|
name: 03 - Create and upload release
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
|
||||||
|
needs: [macos_build, linux_build, windows_build]
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
steps:
|
||||||
|
- name: Get Metadata
|
||||||
|
id: metadata
|
||||||
|
run: |
|
||||||
|
## METADATA SCRIPT
|
||||||
|
echo "::set-output name=version::${GITHUB_REF/refs\/tags\//}"
|
||||||
|
|
||||||
|
- name: Download build artifacts
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
|
||||||
|
- name: Generate Checksums
|
||||||
|
run: |
|
||||||
|
## CHECKSUM GENERATION SCRIPT
|
||||||
|
shopt -s extglob
|
||||||
|
echo "### Checksums" > ${{ github.workspace }}/CHECKSUMS.txt
|
||||||
|
for file in ${{ github.workspace }}/**/@(*.pkg|*.exe|*.deb|*.zip); do
|
||||||
|
echo " ${file##*/}: $(sha256sum "${file}" | cut -d " " -f 1)" >> ${{ github.workspace }}/CHECKSUMS.txt
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5
|
||||||
|
with:
|
||||||
|
draft: true
|
||||||
|
prerelease: ${{ contains(steps.metadata.outputs.version, 'rc') || contains(steps.metadata.outputs.version, 'beta') }}
|
||||||
|
tag_name: ${{ steps.metadata.outputs.version }}
|
||||||
|
name: "${{ env.PLUGIN_NAME }} ${{ steps.metadata.outputs.version }}"
|
||||||
|
body_path: ${{ github.workspace }}/CHECKSUMS.txt
|
||||||
|
files: |
|
||||||
|
${{ github.workspace }}/**/*.zip
|
||||||
|
${{ github.workspace }}/**/*.exe
|
||||||
|
${{ github.workspace }}/**/*.deb
|
||||||
|
${{ github.workspace }}/**/*.pkg
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,5 +1,10 @@
|
|||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
/build/
|
/build/
|
||||||
/build32/
|
/build32/
|
||||||
/build64/
|
/build64/
|
||||||
/release/
|
/release/
|
||||||
|
/package/
|
||||||
/installer/Output/
|
/installer/Output/
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
9
.gitmodules
vendored
9
.gitmodules
vendored
@ -1,3 +1,6 @@
|
|||||||
[submodule "deps/mbedtls"]
|
[submodule "deps/websocketpp"]
|
||||||
path = deps/mbedtls
|
path = deps/websocketpp
|
||||||
url = https://github.com/ARMmbed/mbedtls
|
url = https://github.com/zaphoyd/websocketpp.git
|
||||||
|
[submodule "deps/asio"]
|
||||||
|
path = deps/asio
|
||||||
|
url = https://github.com/chriskohlhoff/asio.git
|
||||||
|
66
BUILDING.md
Normal file
66
BUILDING.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# Compiling obs-websocket
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
You'll need [Qt 5.15.2](https://download.qt.io/official_releases/qt/5.15/5.15.2/),
|
||||||
|
[CMake](https://cmake.org/download/) and a working [OBS Studio development environment](https://obsproject.com/wiki/install-instructions) installed on your
|
||||||
|
computer.
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
|
||||||
|
In cmake-gui, you'll have to set the following variables :
|
||||||
|
|
||||||
|
- **QTDIR** (path) : location of the Qt environment suited for your compiler and architecture
|
||||||
|
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source code of OBS Studio
|
||||||
|
- **LIBOBS_LIB** (filepath) : location of the obs.lib file
|
||||||
|
- **OBS_FRONTEND_LIB** (filepath) : location of the obs-frontend-api.lib file
|
||||||
|
|
||||||
|
## Linux
|
||||||
|
|
||||||
|
On Debian/Ubuntu :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sudo apt-get install libboost-all-dev
|
||||||
|
git clone --recursive https://github.com/Palakis/obs-websocket.git
|
||||||
|
cd obs-websocket
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake -DLIBOBS_INCLUDE_DIR="<path to the libobs sub-folder in obs-studio's source code>" -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=true ..
|
||||||
|
make -j4
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
On other linux OS's, use this cmake command instead:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cmake -DLIBOBS_INCLUDE_DIR="<path to the libobs sub-folder in obs-studio's source code>" -DCMAKE_INSTALL_PREFIX=/usr ..
|
||||||
|
```
|
||||||
|
|
||||||
|
## OS X
|
||||||
|
|
||||||
|
As a prerequisite, you will need Xcode for your current OSX version, the Xcode command line tools, and [Homebrew](https://brew.sh/).
|
||||||
|
Homebrew's setup will guide you in getting your system set up, you should be good to go once Homebrew is successfully up and running.
|
||||||
|
|
||||||
|
Use of the macOS CI scripts is recommended. Please note that these
|
||||||
|
scripts install new software and can change several settings on your system. An
|
||||||
|
existing obs-studio development environment is not required, as
|
||||||
|
`install-build-obs-macos.sh` will install it for you. If you already have a
|
||||||
|
working obs-studio development environment and have built obs-studio, you can
|
||||||
|
skip that script.
|
||||||
|
|
||||||
|
Of course, you're encouraged to dig through the contents of these scripts to
|
||||||
|
look for issues or specificities.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git clone --recursive https://github.com/Palakis/obs-websocket.git
|
||||||
|
cd obs-websocket
|
||||||
|
./CI/macos/install-dependencies-macos.sh
|
||||||
|
./CI/macos/install-build-obs-macos.sh
|
||||||
|
./CI/macos/build-plugin-macos.sh
|
||||||
|
./CI/macos/package-plugin-macos.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This will result in a ready-to-use `obs-websocket.pkg` installer in the `release` subfolder.
|
||||||
|
|
||||||
|
## Automated Builds
|
||||||
|
|
||||||
|
[](https://dev.azure.com/Palakis/obs-websocket/_build/latest?definitionId=2&branchName=4.x-current)
|
176
CMakeLists.txt
176
CMakeLists.txt
@ -1,79 +1,117 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.16...3.21)
|
||||||
project(obs-websocket)
|
|
||||||
|
|
||||||
set(CMAKE_PREFIX_PATH "${QTDIR}")
|
project(obs-websocket-compat VERSION 4.9.1)
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
add_library(${CMAKE_PROJECT_NAME} MODULE)
|
||||||
set(CMAKE_AUTOMOC ON)
|
|
||||||
set(CMAKE_AUTOUIC ON)
|
|
||||||
|
|
||||||
include(external/FindLibObs.cmake)
|
set(PLUGIN_AUTHOR "OBS Project")
|
||||||
find_package(LibObs REQUIRED)
|
|
||||||
find_package(Qt5Core REQUIRED)
|
|
||||||
find_package(Qt5WebSockets REQUIRED)
|
|
||||||
find_package(Qt5Widgets REQUIRED)
|
|
||||||
|
|
||||||
add_subdirectory(deps/mbedtls EXCLUDE_FROM_ALL)
|
set(MACOS_BUNDLEID "com.obsproject.${CMAKE_PROJECT_NAME}")
|
||||||
set(ENABLED_PROGRAMS false)
|
|
||||||
|
|
||||||
set(obs-websocket_SOURCES
|
set(LINUX_MAINTAINER_EMAIL "tt2468@irltoolkit.com")
|
||||||
obs-websocket.cpp
|
|
||||||
WSServer.cpp
|
|
||||||
WSRequestHandler.cpp
|
|
||||||
WSEvents.cpp
|
|
||||||
Config.cpp
|
|
||||||
Utils.cpp
|
|
||||||
forms/settings-dialog.cpp)
|
|
||||||
|
|
||||||
set(obs-websocket_HEADERS
|
target_compile_definitions(obs-websocket-compat PRIVATE ASIO_STANDALONE)
|
||||||
obs-websocket.h
|
|
||||||
WSServer.h
|
|
||||||
WSRequestHandler.h
|
|
||||||
WSEvents.h
|
|
||||||
Config.h
|
|
||||||
Utils.h
|
|
||||||
forms/settings-dialog.h)
|
|
||||||
|
|
||||||
add_library(obs-websocket MODULE
|
target_sources(
|
||||||
${obs-websocket_SOURCES}
|
${CMAKE_PROJECT_NAME}
|
||||||
${obs-websocket_HEADERS})
|
PRIVATE src/obs-websocket.cpp
|
||||||
add_dependencies(obs-websocket mbedcrypto)
|
src/WSServer.cpp
|
||||||
include_directories(
|
src/ConnectionProperties.cpp
|
||||||
"${LIBOBS_INCLUDE_DIR}/../UI/obs-frontend-api"
|
src/WSRequestHandler.cpp
|
||||||
${Qt5Core_INCLUDES}
|
src/WSRequestHandler_General.cpp
|
||||||
${Qt5WebSockets_INCLUDES}
|
src/WSRequestHandler_Profiles.cpp
|
||||||
${Qt5Widgets_INCLUDES}
|
src/WSRequestHandler_Recording.cpp
|
||||||
${mbedcrypto_INCLUDES}
|
src/WSRequestHandler_ReplayBuffer.cpp
|
||||||
"${CMAKE_SOURCE_DIR}/deps/mbedtls/include")
|
src/WSRequestHandler_SceneCollections.cpp
|
||||||
target_link_libraries(obs-websocket
|
src/WSRequestHandler_Scenes.cpp
|
||||||
libobs
|
src/WSRequestHandler_SceneItems.cpp
|
||||||
Qt5::Core
|
src/WSRequestHandler_Sources.cpp
|
||||||
Qt5::WebSockets
|
src/WSRequestHandler_Streaming.cpp
|
||||||
Qt5::Widgets
|
src/WSRequestHandler_VirtualCam.cpp
|
||||||
mbedcrypto)
|
src/WSRequestHandler_StudioMode.cpp
|
||||||
|
src/WSRequestHandler_Transitions.cpp
|
||||||
|
src/WSRequestHandler_Outputs.cpp
|
||||||
|
src/WSRequestHandler_MediaControl.cpp
|
||||||
|
src/WSEvents.cpp
|
||||||
|
src/Config.cpp
|
||||||
|
src/Utils.cpp
|
||||||
|
src/rpc/RpcRequest.cpp
|
||||||
|
src/rpc/RpcResponse.cpp
|
||||||
|
src/rpc/RpcEvent.cpp
|
||||||
|
src/protocol/OBSRemoteProtocol.cpp
|
||||||
|
src/forms/settings-dialog.cpp
|
||||||
|
src/obs-websocket.h
|
||||||
|
src/WSServer.h
|
||||||
|
src/ConnectionProperties.h
|
||||||
|
src/WSRequestHandler.h
|
||||||
|
src/WSEvents.h
|
||||||
|
src/Config.h
|
||||||
|
src/Utils.h
|
||||||
|
src/rpc/RpcRequest.h
|
||||||
|
src/rpc/RpcResponse.h
|
||||||
|
src/rpc/RpcEvent.h
|
||||||
|
src/protocol/OBSRemoteProtocol.h
|
||||||
|
src/forms/settings-dialog.h)
|
||||||
|
|
||||||
if(WIN32)
|
target_include_directories(
|
||||||
set(OBS_FRONTEND_LIB "OBS_FRONTEND_LIB-NOTFOUND" CACHE FILEPATH "OBS frontend library")
|
obs-websocket-compat PRIVATE ${CMAKE_SOURCE_DIR}/deps/asio/asio/include
|
||||||
if(OBS_FRONTEND_LIB EQUAL "OBS_FRONTEND_LIB-NOTFOUND")
|
${CMAKE_SOURCE_DIR}/deps/websocketpp)
|
||||||
message(FATAL_ERROR "Could not find OBS Frontend API\'s library !")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(obs-websocket
|
# /!\ TAKE NOTE: No need to edit things past this point /!\
|
||||||
"${OBS_FRONTEND_LIB}")
|
|
||||||
add_custom_command(TARGET obs-websocket POST_BUILD
|
find_package(libobs REQUIRED)
|
||||||
COMMAND "${CMAKE_COMMAND}" -E copy
|
find_package(obs-frontend-api REQUIRED)
|
||||||
"${QTDIR}/bin/Qt5WebSockets.dll"
|
include(cmake/ObsPluginHelpers.cmake)
|
||||||
"${QTDIR}/bin/Qt5Network.dll"
|
find_qt(COMPONENTS Widgets Core)
|
||||||
"${CMAKE_BINARY_DIR}/$<CONFIG>")
|
|
||||||
|
# --- Platform-independent build settings ---
|
||||||
|
|
||||||
|
target_include_directories(${CMAKE_PROJECT_NAME}
|
||||||
|
PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
${CMAKE_PROJECT_NAME} PRIVATE OBS::libobs OBS::obs-frontend-api Qt::Core
|
||||||
|
Qt::Widgets)
|
||||||
|
|
||||||
|
set_target_properties(
|
||||||
|
${CMAKE_PROJECT_NAME}
|
||||||
|
PROPERTIES AUTOMOC ON
|
||||||
|
AUTOUIC ON
|
||||||
|
AUTORCC ON)
|
||||||
|
|
||||||
|
target_compile_features(${CMAKE_PROJECT_NAME} PRIVATE cxx_std_17)
|
||||||
|
|
||||||
|
# --- End of section ---
|
||||||
|
|
||||||
|
# --- Windows-specific build settings and tasks ---
|
||||||
|
if(OS_WINDOWS)
|
||||||
|
configure_file(cmake/bundle/windows/installer-Windows.iss.in
|
||||||
|
${CMAKE_BINARY_DIR}/installer-Windows.generated.iss)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE /MP /d2FH4-)
|
||||||
|
endif()
|
||||||
|
# --- End of section ---
|
||||||
|
|
||||||
|
# -- macOS specific build settings and tasks --
|
||||||
|
elseif(OS_MACOS)
|
||||||
|
configure_file(cmake/bundle/macos/installer-macos.pkgproj.in
|
||||||
|
${CMAKE_BINARY_DIR}/installer-macos.generated.pkgproj)
|
||||||
|
|
||||||
|
set(MACOSX_PLUGIN_GUI_IDENTIFIER "${MACOS_BUNDLEID}")
|
||||||
|
set(MACOSX_PLUGIN_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION}")
|
||||||
|
set(MACOSX_PLUGIN_SHORT_VERSION_STRING "1")
|
||||||
|
|
||||||
|
target_compile_options(
|
||||||
|
${CMAKE_PROJECT_NAME} PRIVATE -Werror-implicit-function-declaration
|
||||||
|
-stdlib=libc++ -fvisibility=default)
|
||||||
|
|
||||||
|
set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES PREFIX "")
|
||||||
|
# --- End of section ---
|
||||||
|
|
||||||
|
# --- Linux-specific build settings and tasks ---
|
||||||
|
else()
|
||||||
|
set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES PREFIX "")
|
||||||
endif()
|
endif()
|
||||||
|
# --- End of section ---
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
setup_plugin_target(${CMAKE_PROJECT_NAME})
|
||||||
target_compile_options(mbedcrypto PRIVATE -fPIC)
|
|
||||||
set_target_properties(obs-websocket PROPERTIES PREFIX "")
|
|
||||||
target_link_libraries(obs-websocket
|
|
||||||
obs-frontend-api)
|
|
||||||
|
|
||||||
install(TARGETS obs-websocket
|
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/obs-plugins)
|
|
||||||
install(FILES data/locale/en-US.ini data/locale/fr-FR.ini
|
|
||||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/obs/obs-plugins/obs-websocket/locale")
|
|
||||||
endif()
|
|
||||||
|
82
CONTRIBUTING.md
Normal file
82
CONTRIBUTING.md
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
# Contributing to obs-websocket
|
||||||
|
|
||||||
|
## Translating obs-websocket to your language
|
||||||
|
|
||||||
|
Localization happens on [Crowdin](https://crowdin.com/project/obs-websocket)
|
||||||
|
|
||||||
|
## Branches
|
||||||
|
|
||||||
|
**Development happens on `4.x-current`**
|
||||||
|
|
||||||
|
## Writing code for obs-websocket
|
||||||
|
|
||||||
|
### Code Formatting Guidelines
|
||||||
|
|
||||||
|
* Function and variable names: snake_case for C names, camelCase for C++ method names
|
||||||
|
|
||||||
|
* Request and Event names should use MixedCaps names
|
||||||
|
|
||||||
|
* Request and Event json properties should use camelCase. For more detailed info on property naming, see [Google's JSON Style Guide](https://google.github.io/styleguide/jsoncstyleguide.xml)
|
||||||
|
|
||||||
|
* Code is indented with Tabs. Assume they are 8 columns wide
|
||||||
|
|
||||||
|
* 80 columns max code width. (Docs can be larger)
|
||||||
|
|
||||||
|
* New and updated requests/events must always come with accompanying documentation comments (see existing protocol elements for examples).
|
||||||
|
These are required to automatically generate the [protocol specification document](docs/generated/protocol.md).
|
||||||
|
|
||||||
|
### Code Best-Practices
|
||||||
|
|
||||||
|
* Favor return-early code and avoid wrapping huge portions of code in conditionals. As an example, this:
|
||||||
|
```cpp
|
||||||
|
if (success) {
|
||||||
|
return req->SendOKResponse();
|
||||||
|
} else {
|
||||||
|
return req->SendErrorResponse("something went wrong");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
is better like this:
|
||||||
|
```cpp
|
||||||
|
if (!success) {
|
||||||
|
return req->SendErrorResponse("something went wrong");
|
||||||
|
}
|
||||||
|
return req->SendOKResponse();
|
||||||
|
```
|
||||||
|
|
||||||
|
* Some example common response/request property names are:
|
||||||
|
* `sceneName` - The name of a scene
|
||||||
|
* `sourceName` - The name of a source
|
||||||
|
* `fromScene` - From a scene - scene name
|
||||||
|
|
||||||
|
### Commit Guidelines
|
||||||
|
|
||||||
|
* Commits follow the 50/72 standard:
|
||||||
|
* 50 characters max for the commit title (excluding scope name)
|
||||||
|
* One empty line after the title
|
||||||
|
* Description wrapped to 72 columns max width per line.
|
||||||
|
|
||||||
|
* Commit titles:
|
||||||
|
* Use present tense
|
||||||
|
* Prefix the title with a "scope" name
|
||||||
|
* e.g: "CI: fix wrong behaviour when packaging for OS X"
|
||||||
|
* Typical scopes: CI, General, Requests, Events, Server
|
||||||
|
|
||||||
|
**Example commit:**
|
||||||
|
|
||||||
|
```
|
||||||
|
Requests: Add GetTransitionPosition
|
||||||
|
|
||||||
|
Adds a new request called `GetTransitionPosition` which gets the current
|
||||||
|
transition's state from 0.0f to 1.0f. Works with both auto and manual
|
||||||
|
transitions.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pull Requests
|
||||||
|
|
||||||
|
* Pull Requests must never be based off your fork's main branch (in this case, `4.x-current`).
|
||||||
|
* Start your work in a newly named branch based on the upstream main one (e.g.: `feature/cool-new-feature`, `bugfix/fix-palakis-mistakes`, ...)
|
||||||
|
|
||||||
|
* Only open a pull request if you are ready to show off your work.
|
||||||
|
|
||||||
|
* If your work is not done yet, but for any reason you need to PR it (like collecting discussions, testing with CI, getting testers),
|
||||||
|
create it as a Draft Pull Request (open the little arrow menu next to the "Create pull request" button, then select "Create draft pull request").
|
153
Config.cpp
153
Config.cpp
@ -1,153 +0,0 @@
|
|||||||
/*
|
|
||||||
obs-websocket
|
|
||||||
Copyright (C) 2016 Stéphane Lepin <stephane.lepin@gmail.com>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <mbedtls/base64.h>
|
|
||||||
#include <mbedtls/sha256.h>
|
|
||||||
#include <obs-frontend-api.h>
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
#define CONFIG_SECTION_NAME "obs-websocket"
|
|
||||||
#define CONFIG_PARAM_SECRET "auth_hash"
|
|
||||||
#define CONFIG_PARAM_SALT "auth_salt"
|
|
||||||
#define CONFIG_PARAM_AUTHREQUIRED "auth_required"
|
|
||||||
|
|
||||||
Config *Config::_instance = new Config();
|
|
||||||
|
|
||||||
Config::Config() {
|
|
||||||
// Default settings
|
|
||||||
AuthRequired = false;
|
|
||||||
Secret = "";
|
|
||||||
Salt = "";
|
|
||||||
SettingsLoaded = false;
|
|
||||||
|
|
||||||
mbedtls_entropy_init(&entropy);
|
|
||||||
mbedtls_ctr_drbg_init(&rng);
|
|
||||||
mbedtls_ctr_drbg_seed(&rng, mbedtls_entropy_func, &entropy, nullptr, 0);
|
|
||||||
//mbedtls_ctr_drbg_set_prediction_resistance(&rng, MBEDTLS_CTR_DRBG_PR_ON);
|
|
||||||
|
|
||||||
SessionChallenge = GenerateSalt();
|
|
||||||
}
|
|
||||||
|
|
||||||
Config::~Config() {
|
|
||||||
mbedtls_ctr_drbg_free(&rng);
|
|
||||||
mbedtls_entropy_free(&entropy);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* Config::GenerateSalt() {
|
|
||||||
// Generate 32 random chars
|
|
||||||
unsigned char *random_chars = (unsigned char *)bzalloc(32);
|
|
||||||
mbedtls_ctr_drbg_random(&rng, random_chars, 32);
|
|
||||||
|
|
||||||
// Convert the 32 random chars to a base64 string
|
|
||||||
unsigned char *salt = (unsigned char*)bzalloc(64);
|
|
||||||
size_t salt_bytes;
|
|
||||||
mbedtls_base64_encode(salt, 64, &salt_bytes, random_chars, 32);
|
|
||||||
salt[salt_bytes] = 0; // Null-terminate the string
|
|
||||||
|
|
||||||
bfree(random_chars);
|
|
||||||
return (char *)salt;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* Config::GenerateSecret(const char *password, const char *salt) {
|
|
||||||
size_t passwordLength = strlen(password);
|
|
||||||
size_t saltLength = strlen(salt);
|
|
||||||
|
|
||||||
// Concatenate the password and the salt
|
|
||||||
unsigned char *passAndSalt = (unsigned char*)bzalloc(passwordLength + saltLength);
|
|
||||||
memcpy(passAndSalt, password, passwordLength);
|
|
||||||
memcpy(passAndSalt + passwordLength, salt, saltLength);
|
|
||||||
passAndSalt[passwordLength + saltLength] = 0; // Null-terminate the string
|
|
||||||
|
|
||||||
// Generate a SHA256 hash of the password
|
|
||||||
unsigned char *challengeHash = (unsigned char *)bzalloc(32);
|
|
||||||
mbedtls_sha256(passAndSalt, passwordLength + saltLength, challengeHash, 0);
|
|
||||||
|
|
||||||
// Encode SHA256 hash to Base64
|
|
||||||
unsigned char *challenge = (unsigned char*)bzalloc(64);
|
|
||||||
size_t challenge_bytes = 0;
|
|
||||||
mbedtls_base64_encode(challenge, 64, &challenge_bytes, challengeHash, 32);
|
|
||||||
challenge[64] = 0; // Null-terminate the string
|
|
||||||
|
|
||||||
bfree(passAndSalt);
|
|
||||||
bfree(challengeHash);
|
|
||||||
return (char*)challenge;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Config::SetPassword(const char *password) {
|
|
||||||
const char *new_salt = GenerateSalt();
|
|
||||||
const char *new_challenge = GenerateSecret(password, new_salt);
|
|
||||||
|
|
||||||
this->Salt = new_salt;
|
|
||||||
this->Secret = new_challenge;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Config::CheckAuth(const char *response) {
|
|
||||||
size_t secretLength = strlen(this->Secret);
|
|
||||||
size_t sessChallengeLength = strlen(this->SessionChallenge);
|
|
||||||
|
|
||||||
// Concatenate auth secret with the challenge sent to the user
|
|
||||||
char *challengeAndResponse = (char*)bzalloc(secretLength + sessChallengeLength);
|
|
||||||
memcpy(challengeAndResponse, this->Secret, secretLength);
|
|
||||||
memcpy(challengeAndResponse + secretLength, this->SessionChallenge, sessChallengeLength);
|
|
||||||
challengeAndResponse[secretLength + sessChallengeLength] = 0; // Null-terminate the string
|
|
||||||
|
|
||||||
// Generate a SHA256 hash of challengeAndResponse
|
|
||||||
unsigned char *hash = (unsigned char*)bzalloc(32);
|
|
||||||
mbedtls_sha256((unsigned char*)challengeAndResponse, secretLength + sessChallengeLength, hash, 0);
|
|
||||||
|
|
||||||
// Encode the SHA256 hash to Base64
|
|
||||||
unsigned char *expected_response = (unsigned char*)bzalloc(64);
|
|
||||||
size_t base64_size = 0;
|
|
||||||
mbedtls_base64_encode(expected_response, 64, &base64_size, hash, 32);
|
|
||||||
expected_response[64] = 0; // Null-terminate the string
|
|
||||||
|
|
||||||
if (strcmp((char*)expected_response, response) == 0) {
|
|
||||||
SessionChallenge = GenerateSalt();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Config::OBSSaveCallback(obs_data_t *save_data, bool saving, void *private_data) {
|
|
||||||
Config *conf = static_cast<Config *>(private_data);
|
|
||||||
|
|
||||||
if (saving) {
|
|
||||||
obs_data_t *settings = obs_data_create();
|
|
||||||
obs_data_set_bool(settings, CONFIG_PARAM_AUTHREQUIRED, conf->AuthRequired);
|
|
||||||
obs_data_set_string(settings, CONFIG_PARAM_SECRET, conf->Secret);
|
|
||||||
obs_data_set_string(settings, CONFIG_PARAM_SALT, conf->Salt);
|
|
||||||
|
|
||||||
obs_data_set_obj(save_data, CONFIG_SECTION_NAME, settings);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
obs_data_t *settings = obs_data_get_obj(save_data, CONFIG_SECTION_NAME);
|
|
||||||
if (settings) {
|
|
||||||
conf->AuthRequired = obs_data_get_bool(settings, CONFIG_PARAM_AUTHREQUIRED);
|
|
||||||
conf->Secret = obs_data_get_string(settings, CONFIG_PARAM_SECRET);
|
|
||||||
conf->Salt = obs_data_get_string(settings, CONFIG_PARAM_SALT);
|
|
||||||
|
|
||||||
conf->SettingsLoaded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Config* Config::Current() {
|
|
||||||
return _instance;
|
|
||||||
}
|
|
50
Config.h
50
Config.h
@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
obs-websocket
|
|
||||||
Copyright (C) 2016 Stéphane Lepin <stephane.lepin@gmail.com>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CONFIG_H
|
|
||||||
#define CONFIG_H
|
|
||||||
|
|
||||||
#include <obs-module.h>
|
|
||||||
#include <mbedtls/entropy.h>
|
|
||||||
#include <mbedtls/ctr_drbg.h>
|
|
||||||
|
|
||||||
class Config {
|
|
||||||
public:
|
|
||||||
Config();
|
|
||||||
~Config();
|
|
||||||
void SetPassword(const char *password);
|
|
||||||
bool CheckAuth(const char *userChallenge);
|
|
||||||
const char* GenerateSalt();
|
|
||||||
static const char* GenerateSecret(const char *password, const char *salt);
|
|
||||||
static void OBSSaveCallback(obs_data_t *save_data, bool saving, void *);
|
|
||||||
|
|
||||||
bool AuthRequired;
|
|
||||||
const char *Secret;
|
|
||||||
const char *Salt;
|
|
||||||
const char *SessionChallenge;
|
|
||||||
bool SettingsLoaded;
|
|
||||||
|
|
||||||
static Config* Current();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static Config *_instance;
|
|
||||||
mbedtls_entropy_context entropy;
|
|
||||||
mbedtls_ctr_drbg_context rng;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CONFIG_H
|
|
241
PROTOCOL.md
241
PROTOCOL.md
@ -1,241 +0,0 @@
|
|||||||
obs-websocket protocol reference
|
|
||||||
================================
|
|
||||||
|
|
||||||
## General Introduction
|
|
||||||
Messages exchanged between the client and the server are JSON objects.
|
|
||||||
The protocol in general is based on the OBS Remote protocol created by Bill Hamilton, with new commands specific to OBS Studio.
|
|
||||||
|
|
||||||
### Table of contents
|
|
||||||
- [Events](#events)
|
|
||||||
- [Requests](#requests)
|
|
||||||
- [Authentication](#authentication)
|
|
||||||
|
|
||||||
## Events
|
|
||||||
### Description
|
|
||||||
Events are sent exclusively by the server and broadcast to each connected client.
|
|
||||||
An event message will contain at least one field :
|
|
||||||
- **update-type** (string) : the type of event
|
|
||||||
|
|
||||||
Additional fields will be present in the event message depending on the event type.
|
|
||||||
|
|
||||||
### Event Types
|
|
||||||
#### "SwitchScenes"
|
|
||||||
OBS is switching to another scene.
|
|
||||||
- **scene-name** (string) : The name of the scene being switched to.
|
|
||||||
|
|
||||||
#### "ScenesChanged"
|
|
||||||
The scene list has been modified (Scenes have been added, removed, or renamed).
|
|
||||||
|
|
||||||
#### "StreamStarting"
|
|
||||||
A request to start streaming has been issued.
|
|
||||||
- **preview-only** (bool) : Always false.
|
|
||||||
|
|
||||||
#### "StreamStarted"
|
|
||||||
Streaming started successfully.
|
|
||||||
*New in OBS Studio*
|
|
||||||
|
|
||||||
#### "StreamStopping"
|
|
||||||
A request to stop streaming has been issued.
|
|
||||||
- **preview-only** (bool) : Always false.
|
|
||||||
|
|
||||||
#### "StreamStopped"
|
|
||||||
Streaming stopped successfully.
|
|
||||||
*New in OBS Studio*
|
|
||||||
|
|
||||||
#### "RecordingStarting"
|
|
||||||
A request to start recording has been issued.
|
|
||||||
*New in OBS Studio*
|
|
||||||
|
|
||||||
#### "RecordingStarted"
|
|
||||||
Recording started successfully.
|
|
||||||
*New in OBS Studio*
|
|
||||||
|
|
||||||
#### "RecordingStopping"
|
|
||||||
A request to stop streaming has been issued.
|
|
||||||
*New in OBS Studio*
|
|
||||||
|
|
||||||
#### "RecordingStopped"
|
|
||||||
Recording stopped successfully.
|
|
||||||
*New in OBS Studio*
|
|
||||||
|
|
||||||
#### "StreamStatus"
|
|
||||||
Sent every 2 seconds with the following information :
|
|
||||||
- **streaming** (bool) : Current Streaming state.
|
|
||||||
- **recording** (bool) : Current Recording state.
|
|
||||||
- **preview-only** (bool) : Always false.
|
|
||||||
- **bytes-per-sec** (integer) : Amount of data per second (in bytes) transmitted by the stream encoder.
|
|
||||||
- **kbits-per-sec** (integer) : "bytes-per-sec" converted to kilobits per second
|
|
||||||
- **strain** (double) : Percentage of dropped frames
|
|
||||||
- **total-stream-time** (integer) : Total time (in seconds) since the stream started.
|
|
||||||
- **num-total-frames** (integer) : Total number of frames transmitted since the stream started.
|
|
||||||
- **num-dropped-frames** (integer) : Number of frames dropped by the encoder since the stream started.
|
|
||||||
- **fps** (double) : Current framerate.
|
|
||||||
|
|
||||||
#### "Exiting"
|
|
||||||
*New in OBS Studio*
|
|
||||||
OBS is exiting.
|
|
||||||
|
|
||||||
## Requests
|
|
||||||
|
|
||||||
### Description
|
|
||||||
Requests are sent by the client and must have at least the following two fields :
|
|
||||||
- **"request-type"** (string) : One of the request types listed in the sub-section "[Requests Types](#request-types)".
|
|
||||||
- **"message-id"** (string) : An identifier defined by the client which will be embedded in the server response.
|
|
||||||
|
|
||||||
Depending on the request type additional fields may be required (see the "[Request Types](#request-types)" section below for more information).
|
|
||||||
|
|
||||||
Once a request is sent, the server will return a JSON response with the following fields :
|
|
||||||
- **"message-id"** (string) : The identifier specified in the request.
|
|
||||||
- **"status"** (string) : Response status, will be one of the following : "ok", "error"
|
|
||||||
- **"error"** (string) : The error message associated with an "error" status.
|
|
||||||
|
|
||||||
Depending on the request type additional fields may be present (see the "[Request Types](#request-types)" section below for more information).
|
|
||||||
|
|
||||||
### Request Types
|
|
||||||
#### "GetVersion"
|
|
||||||
Returns the latest version of the plugin and the API.
|
|
||||||
|
|
||||||
__Request fields__ : none
|
|
||||||
__Response__ : always OK, with these additional fields :
|
|
||||||
- **"version"** (double) : OBSRemote API version. Fixed to 1.1 for retrocompatibility.
|
|
||||||
- **"obs-websocket-version"** (string) : obs-websocket version
|
|
||||||
|
|
||||||
#### "GetAuthRequired"
|
|
||||||
Tells the client if authentication is required. If it is, authentication parameters "challenge" and "salt" are passed in the response fields (see "Authentication").
|
|
||||||
|
|
||||||
__Request fields__ : none
|
|
||||||
__Response__ : always OK, with these additional fields :
|
|
||||||
- **"authRequired"** (bool)
|
|
||||||
- **"challenge"** (string)
|
|
||||||
- **"salt"** (string)
|
|
||||||
|
|
||||||
#### "Authenticate"
|
|
||||||
Try to authenticate the client on the server.
|
|
||||||
|
|
||||||
__Request fields__ :
|
|
||||||
- **"auth"** (string) : response to the auth challenge (see "Authentication").
|
|
||||||
|
|
||||||
__Response__ : OK if auth succeeded, error if invalid credentials. No additional fields.
|
|
||||||
|
|
||||||
#### "GetCurrentScene"
|
|
||||||
Get the current scene's name and items.
|
|
||||||
|
|
||||||
__Request fields__ : none
|
|
||||||
__Response__ : always OK, with these additional fields :
|
|
||||||
- **"name"** (string) : name of the current scene
|
|
||||||
- **"sources"** (array of objects) : ordered list of the current scene's items descriptions
|
|
||||||
|
|
||||||
Objects in the "sources" array have the following fields :
|
|
||||||
- **"name"** (string) : name of the source associated with the scene item
|
|
||||||
- **"type"** (string) : internal source type name
|
|
||||||
- **"volume"** (double) : audio volume of the source, ranging from 0.0 to 1.0
|
|
||||||
- **"x"** (double) : X coordinate of the top-left corner of the item in the scene
|
|
||||||
- **"y"** (double) : Y coordinate of the top-left corner of the item in the scene
|
|
||||||
- **"cx"** (double) : width of the item (with scale applied)
|
|
||||||
- **"cy"** (double) : height of the item (with scale applied)
|
|
||||||
|
|
||||||
#### "SetCurrentScene"
|
|
||||||
Switch to the scene specified in "scene-name".
|
|
||||||
|
|
||||||
__Request fields__ :
|
|
||||||
- **"scene-name"** (string) : name of the scene to switch to.
|
|
||||||
|
|
||||||
__Response__ : always OK if scene exists, error if it doesn't. No additional fields
|
|
||||||
|
|
||||||
#### "GetSceneList"
|
|
||||||
List OBS' scenes.
|
|
||||||
|
|
||||||
__Request fields__ : none
|
|
||||||
__Response__ : always OK, with these additional fields :
|
|
||||||
- **"current-scene"** (string) : name of the currently active scene
|
|
||||||
- **"scenes"** (array of objects) : ordered list of scene descriptions (see `GetCurrentScene` for reference)
|
|
||||||
|
|
||||||
#### "SetSourceRender"
|
|
||||||
Show or hide a specific source in the current scene.
|
|
||||||
|
|
||||||
__Request fields__ :
|
|
||||||
- **"source"** (string) : name of the source in the currently active scene.
|
|
||||||
- **"render"** (bool) : desired visibility
|
|
||||||
|
|
||||||
__Response__ : OK if source exists in the current scene, error otherwise.
|
|
||||||
|
|
||||||
#### "StartStopStreaming"
|
|
||||||
Toggle streaming on or off.
|
|
||||||
|
|
||||||
__Request fields__ : none
|
|
||||||
__Response__ : always OK. No additional fields.
|
|
||||||
|
|
||||||
#### "StartStopRecording"
|
|
||||||
Toggle recording on or off.
|
|
||||||
|
|
||||||
__Request fields__ : none
|
|
||||||
__Response__ : always OK. No additional fields.
|
|
||||||
*New in OBS Studio*
|
|
||||||
|
|
||||||
#### "GetStreamingStatus"
|
|
||||||
Get current streaming and recording status.
|
|
||||||
|
|
||||||
__Request fields__ : none
|
|
||||||
__Response__ : always OK, with these additional fields :
|
|
||||||
- **"streaming"** (bool) : streaming status (active or not)
|
|
||||||
- **"recording"** (bool) : recording status (active or not)
|
|
||||||
- **"preview-only"** (bool) : always false. Retrocompat with OBSRemote.
|
|
||||||
|
|
||||||
#### "GetTransitionList"
|
|
||||||
List all transitions available in the frontend's dropdown menu.
|
|
||||||
|
|
||||||
__Request fields__ : none
|
|
||||||
__Response__ : always OK, with these additional fields :
|
|
||||||
- **"current-transition"** (string) : name of the current transition
|
|
||||||
- **"transitions"** (array of objects) : list of transition descriptions
|
|
||||||
|
|
||||||
Objects in the "transitions" array have only one field :
|
|
||||||
- **"name"** (string) : name of the transition
|
|
||||||
|
|
||||||
*New in OBS Studio*
|
|
||||||
|
|
||||||
#### "GetCurrentTransition"
|
|
||||||
Get the name of the currently selected transition in the frontend's dropdown menu.
|
|
||||||
|
|
||||||
__Request fields__ : none
|
|
||||||
__Request__ : always OK, with these additional fields :
|
|
||||||
- **"name"** (string) : name of the selected transition
|
|
||||||
|
|
||||||
*New in OBS Studio*
|
|
||||||
|
|
||||||
#### "SetCurrentTransition"
|
|
||||||
__Request fields__ :
|
|
||||||
- **"transition-name"** (string) : The name of the transition.
|
|
||||||
|
|
||||||
__Response__ : OK if specified transition exists, error otherwise.
|
|
||||||
|
|
||||||
*New in OBS Studio*
|
|
||||||
|
|
||||||
### Authentication
|
|
||||||
A call to `GetAuthRequired` gives the client two elements :
|
|
||||||
- A challenge : a random string that will be used to generate the auth response
|
|
||||||
- A salt : applied to the password when generating the auth response
|
|
||||||
|
|
||||||
The client knows a password and must it to authenticate itself to the server.
|
|
||||||
However, it must keep this password secret, and it is the purpose of the authentication mecanism used by obs-websocket.
|
|
||||||
|
|
||||||
After a call to `GetAuthRequired`, the client knows a password (kept secret), a challenge and a salt (sent by the server).
|
|
||||||
To generate the answer to the auth challenge, follow this procedure :
|
|
||||||
- Concatenate the password with the salt sent by the server (in this order : password + server salt), then generate a binary SHA256 hash of the result and encode the resulting SHA256 binary hash to base64.
|
|
||||||
- Concatenate the base64 secret with the challenge sent by the server (in this order : base64 secret + server challenge), then generate a binary SHA256 hash of the result and encode it to base64.
|
|
||||||
- Voilà, this last base64 string is the auth response. You may now use it to authenticate to the server with the `Authenticate` request.
|
|
||||||
|
|
||||||
Here's how it looks in pseudocode :
|
|
||||||
```
|
|
||||||
password = "supersecretpassword"
|
|
||||||
challenge = "ztTBnnuqrqaKDzRM3xcVdbYm"
|
|
||||||
salt = "PZVbYpvAnZut2SS6JNJytDm9"
|
|
||||||
|
|
||||||
secret_string = password + salt
|
|
||||||
secret_hash = binary_sha256(secret_string)
|
|
||||||
secret = base64_encode(secret_hash)
|
|
||||||
|
|
||||||
auth_response_string = secret + challenge
|
|
||||||
auth_response_hash = binary_sha256(auth_response_string)
|
|
||||||
auth_response = base64_encode(auth_response_hash)
|
|
||||||
```
|
|
146
README.md
146
README.md
@ -1,45 +1,131 @@
|
|||||||
obs-websocket
|
# obs-websocket
|
||||||
==============
|
|
||||||
Websocket API for OBS Studio.
|
WebSockets API for OBS Studio.
|
||||||
|
|
||||||
|
[](https://dev.azure.com/Palakis/obs-websocket/_build/latest?definitionId=2&branchName=4.x-current)
|
||||||
|
[](https://www.codefactor.io/repository/github/palakis/obs-websocket)
|
||||||
|
[](https://twitter.com/LePalakis)
|
||||||
|
[](https://discord.gg/WBaSQ3A)
|
||||||
|
[](https://opencollective.com/obs-websocket)
|
||||||
|
|
||||||
## Downloads
|
## Downloads
|
||||||
Binaries for Windows and Linux are available in the [Releases](https://github.com/Palakis/obs-websocket/releases) section.
|
|
||||||
|
Binaries for Windows, MacOS, and Linux are available in the [Releases](https://github.com/Palakis/obs-websocket/releases) section.
|
||||||
|
|
||||||
|
### Homebrew
|
||||||
|
|
||||||
|
If you're using MacOS you can use Homebrew for installation as well:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
brew install obs-websocket
|
||||||
|
```
|
||||||
|
|
||||||
## Using obs-websocket
|
## Using obs-websocket
|
||||||
The Websocket API server runs on port 4444 and a settings window is available in "Websocket server settings" under OBS' "Tools" menu. The obs-websocket protocol is documented in [PROTOCOL.md](PROTOCOL.md).
|
|
||||||
|
|
||||||
Here's a list of available language APIs for obs-websocket :
|
Here is a list of available web clients: (compatible with tablets and other touch interfaces)
|
||||||
- Javascript (browser & nodejs) : [obs-websocket-js](https://github.com/haganbmj/obs-websocket-js) by haganbmj
|
|
||||||
|
|
||||||
There's currently no frontend available for obs-websocket.
|
- [Niek/obs-web](https://github.com/Niek/obs-web)
|
||||||
|
- [t2t2/obs-tablet-remote](https://github.com/t2t2/obs-tablet-remote)
|
||||||
|
|
||||||
|
It is **highly recommended** to protect obs-websocket with a password against unauthorized control. To do this, open the "Websocket server settings" dialog under OBS' "Tools" menu. In the settings dialogs, you can enable or disable authentication and set a password for it.
|
||||||
|
|
||||||
### Possible use cases
|
### Possible use cases
|
||||||
|
|
||||||
- Remote control OBS from a phone or tablet on the same local network
|
- Remote control OBS from a phone or tablet on the same local network
|
||||||
- Change your stream overlay/graphics based on the current scene (like the AGDQ overlay does)
|
- Change your stream overlay/graphics based on the current scene
|
||||||
- Automate scene switching with a third-party program (e.g. : auto-pilot, foot pedal, ...)
|
- Automate scene switching with a third-party program (e.g. : auto-pilot, foot pedal, ...)
|
||||||
|
|
||||||
|
### For developers
|
||||||
|
|
||||||
|
The server is a typical Websockets server running by default on port 4444 (the port number can be changed in the Settings dialog).
|
||||||
|
The protocol understood by the server is documented in [PROTOCOL.md](docs/generated/protocol.md).
|
||||||
|
|
||||||
|
Here's a list of available language APIs for obs-websocket :
|
||||||
|
- Javascript (browser & nodejs): [obs-websocket-js](https://github.com/haganbmj/obs-websocket-js) by Brendan Hagan
|
||||||
|
- C#/VB.NET: [obs-websocket-dotnet](https://github.com/Palakis/obs-websocket-dotnet)
|
||||||
|
- Python 2 and 3: [obs-websocket-py](https://github.com/Elektordi/obs-websocket-py) by Guillaume Genty a.k.a Elektordi
|
||||||
|
- Python 3.5+ with asyncio: [obs-ws-rc](https://github.com/KirillMysnik/obs-ws-rc) by Kirill Mysnik
|
||||||
|
- Python 3.6+ with asyncio: [simpleobsws](https://github.com/IRLToolkit/simpleobsws) by tt2468
|
||||||
|
- Java 8+: [obs-websocket-java](https://github.com/Twasi/websocket-obs-java) by TwasiNET
|
||||||
|
- Java 11+: [obs-java-client](https://github.com/harm27/obs-java-client) by harm27
|
||||||
|
- Go: [go-obs-websocket](https://github.com/christopher-dG/go-obs-websocket) by Chris de Graaf
|
||||||
|
- Go: [goobs](https://github.com/andreykaipov/goobs) by Andrey Kaipov
|
||||||
|
- Rust: [obws](https://github.com/dnaka91/obws) by dnaka91
|
||||||
|
- Dart: [obs_websocket](https://pub.dev/packages/obs_websocket) by faithoflifedev
|
||||||
|
- HTTP API: [obs-websocket-http](https://github.com/IRLToolkit/obs-websocket-http) by tt2468
|
||||||
|
- CLI: [obs-cli](https://github.com/leafac/obs-cli) by leafac
|
||||||
|
- Godot: [obs-websocket-gd](https://github.com/you-win/obs-websocket-gd) by you-win
|
||||||
|
|
||||||
|
I'd like to know what you're building with or for obs-websocket. If you do something in this fashion, feel free to drop a message in `#project-showoff` in the [discord server!](https://discord.gg/WBaSQ3A)
|
||||||
|
|
||||||
|
### Securing obs-websocket (via TLS/SSL)
|
||||||
|
|
||||||
|
If you are intending to use obs-websocket outside of a LAN environment, it is highly recommended to secure the connection using a tunneling service.
|
||||||
|
|
||||||
|
See the SSL [tunnelling guide](SSL-TUNNELLING.md) for easy instructions on how to encrypt your websocket connection.
|
||||||
|
|
||||||
## Compiling obs-websocket
|
## Compiling obs-websocket
|
||||||
### Prerequisites
|
|
||||||
You'll need QT 5 with QtWebSockets, CMake, and a working development environment for OBS Studio installed on your computer.
|
|
||||||
|
|
||||||
### Windows
|
See the [build instructions](BUILDING.md).
|
||||||
In cmake-gui, you'll have to set the following variables :
|
|
||||||
- **QTDIR** (path) : location of the Qt environment suited for your compiler and architecture
|
|
||||||
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source code of OBS Studio
|
|
||||||
- **LIBOBS_LIB** (filepath) : location of the obs.lib file
|
|
||||||
- **OBS_FRONTEND_LIB** (filepath) : location of the obs-frontend-api.lib file
|
|
||||||
|
|
||||||
### Linux
|
## Contributing
|
||||||
On Debian/Ubuntu :
|
|
||||||
```
|
|
||||||
sudo apt-get install libqt5websockets5-dev
|
|
||||||
git clone --recursive https://github.com/Palakis/obs-websocket.git
|
|
||||||
cd obs-websocket
|
|
||||||
mkdir build && cd build
|
|
||||||
cmake -DLIBOBS_INCLUDE_DIR="<path to the libobs sub-folder in obs-studio's source code>" -DCMAKE_INSTALL_PREFIX=/usr ..
|
|
||||||
make -j4
|
|
||||||
sudo make install
|
|
||||||
```
|
|
||||||
|
|
||||||
### OS X
|
See [the contributing document](/CONTRIBUTING.md)
|
||||||
*To do*
|
|
||||||
|
## Translations
|
||||||
|
|
||||||
|
**Your help is welcome on translations.**
|
||||||
|
|
||||||
|
Please join the localization project on [Crowdin](https://crowdin.com/project/obs-websocket)
|
||||||
|
|
||||||
|
## Special thanks
|
||||||
|
|
||||||
|
Thank you so much to all of the contibutors [(here)](https://github.com/Palakis/obs-websocket/graphs/contributors) for your amazing help.
|
||||||
|
|
||||||
|
And also: special thanks to supporters of the project!
|
||||||
|
|
||||||
|
## Supporters
|
||||||
|
|
||||||
|
These supporters have contributed financially to the project and made possible the addition of several features into obs-websocket. Many thanks to them!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[Support Class](http://supportclass.net) designs and develops professional livestreams, with services ranging from broadcast graphics design and integration to event organization, along many other skills.
|
||||||
|
|
||||||
|
[](http://supportclass.net)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[MediaUnit](http://www.mediaunit.no) is a Norwegian media company developing products and services for the media industry, primarly focused on web and events.
|
||||||
|
|
||||||
|
[](http://www.mediaunit.no/)
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
### Code Contributors
|
||||||
|
|
||||||
|
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||||
|
<a href="https://github.com/Palakis/obs-websocket/graphs/contributors"><img src="https://opencollective.com/obs-websocket/contributors.svg?width=890&button=false" /></a>
|
||||||
|
|
||||||
|
### Financial Contributors
|
||||||
|
|
||||||
|
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/obs-websocket/contribute)]
|
||||||
|
|
||||||
|
#### Individuals
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/obs-websocket"><img src="https://opencollective.com/obs-websocket/individuals.svg?width=890"></a>
|
||||||
|
|
||||||
|
#### Organizations
|
||||||
|
|
||||||
|
Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/obs-websocket/contribute)]
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/obs-websocket/organization/0/website"><img src="https://opencollective.com/obs-websocket/organization/0/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/obs-websocket/organization/1/website"><img src="https://opencollective.com/obs-websocket/organization/1/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/obs-websocket/organization/2/website"><img src="https://opencollective.com/obs-websocket/organization/2/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/obs-websocket/organization/3/website"><img src="https://opencollective.com/obs-websocket/organization/3/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/obs-websocket/organization/4/website"><img src="https://opencollective.com/obs-websocket/organization/4/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/obs-websocket/organization/5/website"><img src="https://opencollective.com/obs-websocket/organization/5/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/obs-websocket/organization/6/website"><img src="https://opencollective.com/obs-websocket/organization/6/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/obs-websocket/organization/7/website"><img src="https://opencollective.com/obs-websocket/organization/7/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/obs-websocket/organization/8/website"><img src="https://opencollective.com/obs-websocket/organization/8/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/obs-websocket/organization/9/website"><img src="https://opencollective.com/obs-websocket/organization/9/avatar.svg"></a>
|
||||||
|
45
SSL-TUNNELLING.md
Normal file
45
SSL-TUNNELLING.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# Connecting over a TLS/secure connection (or remotely)
|
||||||
|
|
||||||
|
If you want to expose the WebSocket server of obs-websocket over a secure TLS connection (or to connect remotely), the easiest approach is to use a localhost tunneling service like [ngrok](https://ngrok.com/) or [pagekite](https://pagekite.net/).
|
||||||
|
|
||||||
|
**Before doing this, secure the WebSocket server first by enabling authentication with a strong password!**
|
||||||
|
|
||||||
|
**Please bear in mind that doing this will expose your OBS instance to the open Internet and the security risks it implies. *You've been warned!***
|
||||||
|
|
||||||
|
|
||||||
|
## ngrok
|
||||||
|
|
||||||
|
[Install the ngrok CLI tool](https://ngrok.com/download) on a linux OS, then start ngrok bound to port 4444 like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ngrok http 4444
|
||||||
|
```
|
||||||
|
|
||||||
|
The ngrok command will output something like this:
|
||||||
|
|
||||||
|
```text
|
||||||
|
ngrok by @inconshreveable
|
||||||
|
|
||||||
|
Tunnel Status online
|
||||||
|
Version 2.0/2.0
|
||||||
|
Web Interface http://127.0.0.1:4040
|
||||||
|
Forwarding http://TUNNEL_ID.ngrok.io -> localhost:4444
|
||||||
|
Forwarding https://TUNNEL_ID.ngrok.io -> localhost:4444
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `TUNNEL_ID` is, as the name implies, the unique name of your ngrok tunnel. You'll get a new one every time you start ngrok.
|
||||||
|
|
||||||
|
Then, use `wss://TUNNEL_ID.ngrok.io` to connect to obs-websocket over TLS.
|
||||||
|
|
||||||
|
See the [ngrok documentation](https://ngrok.com/docs) for more tunneling options and settings.
|
||||||
|
|
||||||
|
|
||||||
|
## PageKite
|
||||||
|
|
||||||
|
[Install the PageKite CLI tool](http://pagekite.net/downloads), then start PageKite bound to port 4444 like this (replace NAME with one of your choosing):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python pagekite.py 4444 NAME.pagekite.me
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, use `wss://NAME.pagekite.me` to connect to obs-websocket over TLS.
|
146
Utils.cpp
146
Utils.cpp
@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
obs-websocket
|
|
||||||
Copyright (C) 2016 Stéphane Lepin <stephane.lepin@gmail.com>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Utils.h"
|
|
||||||
|
|
||||||
obs_data_array_t* Utils::GetSceneItems(obs_source_t *source) {
|
|
||||||
obs_data_array_t *items = obs_data_array_create();
|
|
||||||
obs_scene_t *scene = obs_scene_from_source(source);
|
|
||||||
if (scene == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_scene_enum_items(scene, [](obs_scene_t *scene, obs_sceneitem_t *currentItem, void *param) {
|
|
||||||
obs_data_array_t *data = static_cast<obs_data_array_t *>(param);
|
|
||||||
|
|
||||||
obs_data_t *item_data = GetSceneItemData(currentItem);
|
|
||||||
obs_data_array_insert(data, 0, item_data);
|
|
||||||
|
|
||||||
obs_data_release(item_data);
|
|
||||||
return true;
|
|
||||||
}, items);
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_data_t* Utils::GetSceneItemData(obs_sceneitem_t *item) {
|
|
||||||
if (!item) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 pos;
|
|
||||||
obs_sceneitem_get_pos(item, &pos);
|
|
||||||
|
|
||||||
vec2 bounds;
|
|
||||||
obs_sceneitem_get_bounds(item, &bounds);
|
|
||||||
|
|
||||||
obs_data_t *data = obs_data_create();
|
|
||||||
obs_data_set_string(data, "name", obs_source_get_name(obs_sceneitem_get_source(item)));
|
|
||||||
obs_data_set_string(data, "type", obs_source_get_id(obs_sceneitem_get_source(item)));
|
|
||||||
obs_data_set_double(data, "volume", obs_source_get_volume(obs_sceneitem_get_source(item)));
|
|
||||||
obs_data_set_double(data, "x", pos.x);
|
|
||||||
obs_data_set_double(data, "y", pos.y);
|
|
||||||
obs_data_set_double(data, "cx", bounds.x);
|
|
||||||
obs_data_set_double(data, "cy", bounds.y);
|
|
||||||
obs_data_set_bool(data, "render", obs_sceneitem_visible(item));
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_sceneitem_t* Utils::GetSceneItemFromName(obs_source_t* source, const char* name) {
|
|
||||||
struct current_search {
|
|
||||||
const char* query;
|
|
||||||
obs_sceneitem_t* result;
|
|
||||||
};
|
|
||||||
|
|
||||||
current_search search;
|
|
||||||
search.query = name;
|
|
||||||
search.result = NULL;
|
|
||||||
|
|
||||||
obs_scene_t *scene = obs_scene_from_source(source);
|
|
||||||
if (scene == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_scene_enum_items(scene, [](obs_scene_t *scene, obs_sceneitem_t *currentItem, void *param) {
|
|
||||||
current_search *search = static_cast<current_search *>(param);
|
|
||||||
|
|
||||||
const char* currentItemName = obs_source_get_name(obs_sceneitem_get_source(currentItem));
|
|
||||||
if (strcmp(currentItemName, search->query) == 0) {
|
|
||||||
search->result = currentItem;
|
|
||||||
obs_sceneitem_addref(search->result);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}, &search);
|
|
||||||
|
|
||||||
return search.result;
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_source_t* Utils::GetTransitionFromName(const char *search_name) {
|
|
||||||
obs_source_t *found_transition = NULL;
|
|
||||||
|
|
||||||
obs_frontend_source_list transition_list = {};
|
|
||||||
obs_frontend_get_transitions(&transition_list);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < transition_list.sources.num; i++) {
|
|
||||||
obs_source_t *transition = transition_list.sources.array[i];
|
|
||||||
|
|
||||||
const char *transition_name = obs_source_get_name(transition);
|
|
||||||
if (strcmp(transition_name, search_name) == 0) {
|
|
||||||
found_transition = transition;
|
|
||||||
obs_source_addref(found_transition);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_frontend_source_list_free(&transition_list);
|
|
||||||
|
|
||||||
return found_transition;
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_data_array_t* Utils::GetScenes() {
|
|
||||||
obs_frontend_source_list sceneList = {};
|
|
||||||
obs_frontend_get_scenes(&sceneList);
|
|
||||||
|
|
||||||
obs_data_array_t* scenes = obs_data_array_create();
|
|
||||||
for (size_t i = 0; i < sceneList.sources.num; i++) {
|
|
||||||
obs_source_t *scene = sceneList.sources.array[i];
|
|
||||||
|
|
||||||
obs_data_t *scene_data = GetSceneData(scene);
|
|
||||||
obs_data_array_push_back(scenes, scene_data);
|
|
||||||
|
|
||||||
obs_data_release(scene_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_frontend_source_list_free(&sceneList);
|
|
||||||
|
|
||||||
return scenes;
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_data_t* Utils::GetSceneData(obs_source *source) {
|
|
||||||
obs_data_array_t *scene_items = GetSceneItems(source);
|
|
||||||
|
|
||||||
obs_data_t* sceneData = obs_data_create();
|
|
||||||
obs_data_set_string(sceneData, "name", obs_source_get_name(source));
|
|
||||||
obs_data_set_array(sceneData, "sources", scene_items);
|
|
||||||
|
|
||||||
obs_data_array_release(scene_items);
|
|
||||||
return sceneData;
|
|
||||||
}
|
|
244
WSEvents.cpp
244
WSEvents.cpp
@ -1,244 +0,0 @@
|
|||||||
/*
|
|
||||||
obs-websocket
|
|
||||||
Copyright (C) 2016 Stéphane Lepin <stephane.lepin@gmail.com>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WSEvents.h"
|
|
||||||
|
|
||||||
WSEvents::WSEvents(WSServer *server) {
|
|
||||||
_srv = server;
|
|
||||||
obs_frontend_add_event_callback(WSEvents::FrontendEventHandler, this);
|
|
||||||
|
|
||||||
QTimer *statusTimer = new QTimer();
|
|
||||||
connect(statusTimer, SIGNAL(timeout()), this, SLOT(StreamStatus()));
|
|
||||||
statusTimer->start(2000); // equal to frontend's constant BITRATE_UPDATE_SECONDS
|
|
||||||
}
|
|
||||||
|
|
||||||
WSEvents::~WSEvents() {
|
|
||||||
obs_frontend_remove_event_callback(WSEvents::FrontendEventHandler, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private_data)
|
|
||||||
{
|
|
||||||
WSEvents *owner = static_cast<WSEvents *>(private_data);
|
|
||||||
|
|
||||||
// TODO : implement SourceChanged, SourceOrderChanged and RepopulateSources
|
|
||||||
|
|
||||||
if (event == OBS_FRONTEND_EVENT_SCENE_CHANGED) {
|
|
||||||
owner->OnSceneChange();
|
|
||||||
}
|
|
||||||
else if (event == OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED) {
|
|
||||||
owner->OnSceneListChange();
|
|
||||||
}
|
|
||||||
else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTING) {
|
|
||||||
owner->OnStreamStarting();
|
|
||||||
}
|
|
||||||
else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTED) {
|
|
||||||
owner->OnStreamStarted();
|
|
||||||
}
|
|
||||||
else if (event == OBS_FRONTEND_EVENT_STREAMING_STOPPING) {
|
|
||||||
owner->OnStreamStopping();
|
|
||||||
}
|
|
||||||
else if (event == OBS_FRONTEND_EVENT_STREAMING_STOPPED) {
|
|
||||||
owner->OnStreamStopped();
|
|
||||||
}
|
|
||||||
else if (event == OBS_FRONTEND_EVENT_RECORDING_STARTING) {
|
|
||||||
owner->OnRecordingStarting();
|
|
||||||
}
|
|
||||||
else if (event == OBS_FRONTEND_EVENT_RECORDING_STARTED) {
|
|
||||||
owner->OnRecordingStarted();
|
|
||||||
}
|
|
||||||
else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPING) {
|
|
||||||
owner->OnRecordingStopping();
|
|
||||||
}
|
|
||||||
else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPED) {
|
|
||||||
owner->OnRecordingStopped();
|
|
||||||
}
|
|
||||||
else if (event == OBS_FRONTEND_EVENT_EXIT) {
|
|
||||||
obs_frontend_save();
|
|
||||||
owner->OnExit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::broadcastUpdate(const char *updateType, obs_data_t *additionalFields = NULL) {
|
|
||||||
obs_source_t *source = obs_frontend_get_current_scene();
|
|
||||||
const char *name = obs_source_get_name(source);
|
|
||||||
|
|
||||||
obs_data_t *update = obs_data_create();
|
|
||||||
|
|
||||||
obs_data_set_string(update, "update-type", updateType);
|
|
||||||
if (additionalFields != NULL) {
|
|
||||||
obs_data_apply(update, additionalFields);
|
|
||||||
}
|
|
||||||
|
|
||||||
_srv->broadcast(obs_data_get_json(update));
|
|
||||||
|
|
||||||
obs_data_release(update);
|
|
||||||
obs_source_release(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::OnSceneChange() {
|
|
||||||
// Implements an existing update type from bilhamil's OBS Remote
|
|
||||||
|
|
||||||
// Default behavior : get the new scene from the running transition
|
|
||||||
obs_source_t *transition = obs_frontend_get_current_transition();
|
|
||||||
obs_source_t *new_scene = obs_transition_get_source(transition, OBS_TRANSITION_SOURCE_B);
|
|
||||||
if (!new_scene) {
|
|
||||||
obs_source_release(transition);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *scene_name = obs_source_get_name(new_scene);
|
|
||||||
if (!scene_name) {
|
|
||||||
// Fallback behaviour : get the new scene straight from the API
|
|
||||||
obs_source_release(new_scene);
|
|
||||||
new_scene = obs_frontend_get_current_scene();
|
|
||||||
|
|
||||||
if (new_scene) {
|
|
||||||
scene_name = obs_source_get_name(new_scene);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_data_t *data = obs_data_create();
|
|
||||||
obs_data_set_string(data, "scene-name", scene_name);
|
|
||||||
|
|
||||||
broadcastUpdate("SwitchScenes", data);
|
|
||||||
|
|
||||||
obs_data_release(data);
|
|
||||||
obs_source_release(new_scene);
|
|
||||||
obs_source_release(transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::OnSceneListChange() {
|
|
||||||
broadcastUpdate("ScenesChanged");
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::OnStreamStarting() {
|
|
||||||
// Implements an existing update type from bilhamil's OBS Remote
|
|
||||||
obs_data_t *data = obs_data_create();
|
|
||||||
obs_data_set_bool(data, "preview-only", false);
|
|
||||||
|
|
||||||
broadcastUpdate("StreamStarting", data);
|
|
||||||
|
|
||||||
obs_data_release(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::OnStreamStarted() {
|
|
||||||
// New update type specific to OBS Studio
|
|
||||||
_streamStartTime = os_gettime_ns();
|
|
||||||
_lastBytesSent = 0;
|
|
||||||
broadcastUpdate("StreamStarted");
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::OnStreamStopping() {
|
|
||||||
// Implements an existing update type from bilhamil's OBS Remote
|
|
||||||
obs_data_t *data = obs_data_create();
|
|
||||||
obs_data_set_bool(data, "preview-only", false);
|
|
||||||
|
|
||||||
broadcastUpdate("StreamStopping", data);
|
|
||||||
|
|
||||||
obs_data_release(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::OnStreamStopped() {
|
|
||||||
// New update type specific to OBS Studio
|
|
||||||
_streamStartTime = 0;
|
|
||||||
broadcastUpdate("StreamStopped");
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::OnRecordingStarting() {
|
|
||||||
// New update type specific to OBS Studio
|
|
||||||
broadcastUpdate("RecordingStarting");
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::OnRecordingStarted() {
|
|
||||||
// New update type specific to OBS Studio
|
|
||||||
broadcastUpdate("RecordingStarted");
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::OnRecordingStopping() {
|
|
||||||
// New update type specific to OBS Studio
|
|
||||||
broadcastUpdate("RecordingStopping");
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::OnRecordingStopped() {
|
|
||||||
// New update type specific to OBS Studio
|
|
||||||
broadcastUpdate("RecordingStopped");
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::OnExit() {
|
|
||||||
// New update type specific to OBS Studio
|
|
||||||
broadcastUpdate("Exiting");
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSEvents::StreamStatus() {
|
|
||||||
bool streaming_active = obs_frontend_streaming_active();
|
|
||||||
bool recording_active = obs_frontend_recording_active();
|
|
||||||
|
|
||||||
obs_output_t *stream_output = obs_frontend_get_streaming_output();
|
|
||||||
|
|
||||||
if (!stream_output || !streaming_active) {
|
|
||||||
if (stream_output) {
|
|
||||||
obs_output_release(stream_output);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t bytes_sent = obs_output_get_total_bytes(stream_output);
|
|
||||||
uint64_t bytes_sent_time = os_gettime_ns();
|
|
||||||
|
|
||||||
if (bytes_sent < _lastBytesSent) {
|
|
||||||
bytes_sent = 0;
|
|
||||||
}
|
|
||||||
if (bytes_sent == 0) {
|
|
||||||
_lastBytesSent = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t bytes_between = bytes_sent - _lastBytesSent;
|
|
||||||
double time_passed = double(bytes_sent_time - _lastBytesSentTime) / 1000000000.0;
|
|
||||||
|
|
||||||
uint64_t bytes_per_sec = bytes_between / time_passed;
|
|
||||||
|
|
||||||
_lastBytesSent = bytes_sent;
|
|
||||||
_lastBytesSentTime = bytes_sent_time;
|
|
||||||
|
|
||||||
uint64_t totalStreamTime = (os_gettime_ns() - _streamStartTime) / 1000000000;
|
|
||||||
|
|
||||||
int total_frames = obs_output_get_total_frames(stream_output);
|
|
||||||
int dropped_frames = obs_output_get_frames_dropped(stream_output);
|
|
||||||
|
|
||||||
float strain = 0.0;
|
|
||||||
if (total_frames > 0) {
|
|
||||||
strain = (dropped_frames / total_frames) * 100.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_data_t *data = obs_data_create();
|
|
||||||
obs_data_set_bool(data, "streaming", streaming_active);
|
|
||||||
obs_data_set_bool(data, "recording", recording_active);
|
|
||||||
obs_data_set_int(data, "bytes-per-sec", bytes_per_sec);
|
|
||||||
obs_data_set_int(data, "kbits-per-sec", (bytes_per_sec * 8) / 1024);
|
|
||||||
obs_data_set_int(data, "total-stream-time", totalStreamTime);
|
|
||||||
obs_data_set_int(data, "num-total-frames", total_frames);
|
|
||||||
obs_data_set_int(data, "num-dropped-frames", dropped_frames);
|
|
||||||
obs_data_set_double(data, "fps", obs_get_active_fps());
|
|
||||||
obs_data_set_double(data, "strain", strain);
|
|
||||||
obs_data_set_bool(data, "preview-only", false); // Retrocompat with OBSRemote
|
|
||||||
|
|
||||||
broadcastUpdate("StreamStatus", data);
|
|
||||||
|
|
||||||
obs_data_release(data);
|
|
||||||
obs_output_release(stream_output);
|
|
||||||
}
|
|
63
WSEvents.h
63
WSEvents.h
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
obs-websocket
|
|
||||||
Copyright (C) 2016 Stéphane Lepin <stephane.lepin@gmail.com>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WSEVENTS_H
|
|
||||||
#define WSEVENTS_H
|
|
||||||
|
|
||||||
#include <QtWebSockets/QWebSocket>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <obs-frontend-api.h>
|
|
||||||
#include <util/platform.h>
|
|
||||||
#include "WSServer.h"
|
|
||||||
|
|
||||||
class WSEvents : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit WSEvents(WSServer *server);
|
|
||||||
~WSEvents();
|
|
||||||
static void FrontendEventHandler(enum obs_frontend_event event, void *private_data);
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
|
||||||
void StreamStatus();
|
|
||||||
|
|
||||||
private:
|
|
||||||
WSServer *_srv;
|
|
||||||
uint64_t _streamStartTime;
|
|
||||||
uint64_t _lastBytesSent;
|
|
||||||
uint64_t _lastBytesSentTime;
|
|
||||||
void broadcastUpdate(const char *updateType, obs_data_t *additionalFields);
|
|
||||||
|
|
||||||
void OnSceneChange();
|
|
||||||
void OnSceneListChange();
|
|
||||||
|
|
||||||
void OnStreamStarting();
|
|
||||||
void OnStreamStarted();
|
|
||||||
void OnStreamStopping();
|
|
||||||
void OnStreamStopped();
|
|
||||||
|
|
||||||
void OnRecordingStarting();
|
|
||||||
void OnRecordingStarted();
|
|
||||||
void OnRecordingStopping();
|
|
||||||
void OnRecordingStopped();
|
|
||||||
|
|
||||||
void OnExit();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // WSEVENTS_H
|
|
@ -1,347 +0,0 @@
|
|||||||
/*
|
|
||||||
obs-websocket
|
|
||||||
Copyright (C) 2016 Stéphane Lepin <stephane.lepin@gmail.com>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WSRequestHandler.h"
|
|
||||||
#include "obs-websocket.h"
|
|
||||||
#include "Config.h"
|
|
||||||
#include "Utils.h"
|
|
||||||
|
|
||||||
WSRequestHandler::WSRequestHandler(QWebSocket *client) :
|
|
||||||
_authenticated(false),
|
|
||||||
_messageId(0),
|
|
||||||
_requestType(""),
|
|
||||||
_requestData(nullptr)
|
|
||||||
{
|
|
||||||
_client = client;
|
|
||||||
|
|
||||||
messageMap["GetVersion"] = WSRequestHandler::HandleGetVersion;
|
|
||||||
messageMap["GetAuthRequired"] = WSRequestHandler::HandleGetAuthRequired;
|
|
||||||
messageMap["Authenticate"] = WSRequestHandler::HandleAuthenticate;
|
|
||||||
|
|
||||||
messageMap["SetCurrentScene"] = WSRequestHandler::HandleSetCurrentScene;
|
|
||||||
messageMap["GetCurrentScene"] = WSRequestHandler::HandleGetCurrentScene;
|
|
||||||
messageMap["GetSceneList"] = WSRequestHandler::HandleGetSceneList;
|
|
||||||
messageMap["SetSourceOrder"] = WSRequestHandler::ErrNotImplemented;
|
|
||||||
messageMap["SetSourceRender"] = WSRequestHandler::HandleSetSourceRender;
|
|
||||||
messageMap["SetSceneItemPositionAndSize"] = WSRequestHandler::ErrNotImplemented;
|
|
||||||
messageMap["GetStreamingStatus"] = WSRequestHandler::HandleGetStreamingStatus;
|
|
||||||
messageMap["StartStopStreaming"] = WSRequestHandler::HandleStartStopStreaming;
|
|
||||||
messageMap["StartStopRecording"] = WSRequestHandler::HandleStartStopRecording;
|
|
||||||
messageMap["ToggleMute"] = WSRequestHandler::ErrNotImplemented;
|
|
||||||
messageMap["GetVolumes"] = WSRequestHandler::ErrNotImplemented;
|
|
||||||
messageMap["SetVolume"] = WSRequestHandler::ErrNotImplemented;
|
|
||||||
|
|
||||||
messageMap["GetTransitionList"] = WSRequestHandler::HandleGetTransitionList;
|
|
||||||
messageMap["GetCurrentTransition"] = WSRequestHandler::HandleGetCurrentTransition;
|
|
||||||
messageMap["SetCurrentTransition"] = WSRequestHandler::HandleSetCurrentTransition;
|
|
||||||
|
|
||||||
authNotRequired.insert("GetVersion");
|
|
||||||
authNotRequired.insert("GetAuthRequired");
|
|
||||||
authNotRequired.insert("Authenticate");
|
|
||||||
|
|
||||||
blog(LOG_INFO, "[obs-websockets] new client connected from %s:%d", _client->peerAddress().toString().toLocal8Bit(), _client->peerPort());
|
|
||||||
|
|
||||||
connect(_client, &QWebSocket::textMessageReceived, this, &WSRequestHandler::processTextMessage);
|
|
||||||
connect(_client, &QWebSocket::disconnected, this, &WSRequestHandler::socketDisconnected);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::processTextMessage(QString textMessage) {
|
|
||||||
QByteArray msgData = textMessage.toLocal8Bit();
|
|
||||||
const char *msg = msgData;
|
|
||||||
|
|
||||||
_requestData = obs_data_create_from_json(msg);
|
|
||||||
if (!_requestData) {
|
|
||||||
blog(LOG_ERROR, "[obs-websockets] invalid JSON payload for '%s'", msg);
|
|
||||||
SendErrorResponse("invalid JSON payload");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_requestType = obs_data_get_string(_requestData, "request-type");
|
|
||||||
_messageId = obs_data_get_string(_requestData, "message-id");
|
|
||||||
|
|
||||||
if (Config::Current()->AuthRequired
|
|
||||||
&& !_authenticated
|
|
||||||
&& authNotRequired.find(_requestType) == authNotRequired.end())
|
|
||||||
{
|
|
||||||
SendErrorResponse("Not Authenticated");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void (*handlerFunc)(WSRequestHandler*) = (messageMap[_requestType]);
|
|
||||||
|
|
||||||
if (handlerFunc != NULL) {
|
|
||||||
handlerFunc(this);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SendErrorResponse("invalid request type");
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_data_release(_requestData);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::socketDisconnected() {
|
|
||||||
blog(LOG_INFO, "[obs-websockets] client %s:%d disconnected", _client->peerAddress().toString().toStdString(), _client->peerPort());
|
|
||||||
|
|
||||||
_authenticated = false;
|
|
||||||
_client->deleteLater();
|
|
||||||
emit disconnected();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::sendTextMessage(QString textMessage) {
|
|
||||||
_client->sendTextMessage(textMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WSRequestHandler::isAuthenticated() {
|
|
||||||
return _authenticated;
|
|
||||||
}
|
|
||||||
|
|
||||||
WSRequestHandler::~WSRequestHandler() {
|
|
||||||
if (_requestData != NULL) {
|
|
||||||
obs_data_release(_requestData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::SendOKResponse(obs_data_t *additionalFields) {
|
|
||||||
obs_data_t *response = obs_data_create();
|
|
||||||
obs_data_set_string(response, "status", "ok");
|
|
||||||
obs_data_set_string(response, "message-id", _messageId);
|
|
||||||
|
|
||||||
if (additionalFields != NULL) {
|
|
||||||
obs_data_apply(response, additionalFields);
|
|
||||||
}
|
|
||||||
|
|
||||||
_client->sendTextMessage(obs_data_get_json(response));
|
|
||||||
|
|
||||||
obs_data_release(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::SendErrorResponse(const char *errorMessage) {
|
|
||||||
obs_data_t *response = obs_data_create();
|
|
||||||
obs_data_set_string(response, "status", "error");
|
|
||||||
obs_data_set_string(response, "error", errorMessage);
|
|
||||||
obs_data_set_string(response, "message-id", _messageId);
|
|
||||||
|
|
||||||
_client->sendTextMessage(obs_data_get_json(response));
|
|
||||||
|
|
||||||
obs_data_release(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::HandleGetVersion(WSRequestHandler *owner) {
|
|
||||||
obs_data_t *data = obs_data_create();
|
|
||||||
obs_data_set_double(data, "version", 1.1);
|
|
||||||
obs_data_set_string(data, "obs-websocket-version", OBS_WEBSOCKET_VERSION);
|
|
||||||
//obs_data_set_string(data, "obs-studio-version", OBS_VERSION); // Wrong
|
|
||||||
|
|
||||||
owner->SendOKResponse(data);
|
|
||||||
|
|
||||||
obs_data_release(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::HandleGetAuthRequired(WSRequestHandler *owner) {
|
|
||||||
bool authRequired = Config::Current()->AuthRequired;
|
|
||||||
|
|
||||||
obs_data_t *data = obs_data_create();
|
|
||||||
obs_data_set_bool(data, "authRequired", authRequired);
|
|
||||||
|
|
||||||
if (authRequired) {
|
|
||||||
obs_data_set_string(data, "challenge", Config::Current()->SessionChallenge);
|
|
||||||
obs_data_set_string(data, "salt", Config::Current()->Salt);
|
|
||||||
}
|
|
||||||
|
|
||||||
owner->SendOKResponse(data);
|
|
||||||
|
|
||||||
obs_data_release(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::HandleAuthenticate(WSRequestHandler *owner) {
|
|
||||||
const char *auth = obs_data_get_string(owner->_requestData, "auth");
|
|
||||||
if (!auth || strlen(auth) < 1) {
|
|
||||||
owner->SendErrorResponse("auth not specified!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(owner->_authenticated) && Config::Current()->CheckAuth(auth)) {
|
|
||||||
owner->_authenticated = true;
|
|
||||||
owner->SendOKResponse();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
owner->SendErrorResponse("Authentication Failed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::HandleSetCurrentScene(WSRequestHandler *owner) {
|
|
||||||
const char *sceneName = obs_data_get_string(owner->_requestData, "scene-name");
|
|
||||||
obs_source_t *source = obs_get_source_by_name(sceneName);
|
|
||||||
|
|
||||||
if (source) {
|
|
||||||
obs_frontend_set_current_scene(source);
|
|
||||||
owner->SendOKResponse();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
owner->SendErrorResponse("requested scene does not exist");
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_source_release(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Indirectly causes memory leaks
|
|
||||||
void WSRequestHandler::HandleGetCurrentScene(WSRequestHandler *owner) {
|
|
||||||
obs_source_t *current_scene = obs_frontend_get_current_scene();
|
|
||||||
const char *name = obs_source_get_name(current_scene);
|
|
||||||
|
|
||||||
obs_data_array_t *scene_items = Utils::GetSceneItems(current_scene); // Causes memory leaks
|
|
||||||
|
|
||||||
obs_data_t *data = obs_data_create();
|
|
||||||
obs_data_set_string(data, "name", name);
|
|
||||||
obs_data_set_array(data, "sources", scene_items);
|
|
||||||
|
|
||||||
owner->SendOKResponse(data);
|
|
||||||
|
|
||||||
obs_data_release(data);
|
|
||||||
obs_data_array_release(scene_items);
|
|
||||||
obs_source_release(current_scene);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::HandleGetSceneList(WSRequestHandler *owner) {
|
|
||||||
obs_source_t *current_scene = obs_frontend_get_current_scene();
|
|
||||||
obs_data_array_t *scenes = Utils::GetScenes();
|
|
||||||
|
|
||||||
obs_data_t *data = obs_data_create();
|
|
||||||
obs_data_set_string(data, "current-scene", obs_source_get_name(current_scene));
|
|
||||||
obs_data_set_array(data, "scenes", scenes);
|
|
||||||
|
|
||||||
owner->SendOKResponse(data);
|
|
||||||
|
|
||||||
obs_data_release(data);
|
|
||||||
obs_data_array_release(scenes);
|
|
||||||
obs_source_release(current_scene);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::HandleSetSourceRender(WSRequestHandler *owner) {
|
|
||||||
const char *itemName = obs_data_get_string(owner->_requestData, "source");
|
|
||||||
bool isVisible = obs_data_get_bool(owner->_requestData, "render");
|
|
||||||
if (itemName == NULL) {
|
|
||||||
owner->SendErrorResponse("invalid request parameters");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_source_t* currentScene = obs_frontend_get_current_scene();
|
|
||||||
|
|
||||||
obs_sceneitem_t *sceneItem = Utils::GetSceneItemFromName(currentScene, itemName);
|
|
||||||
if (sceneItem != NULL) {
|
|
||||||
obs_sceneitem_set_visible(sceneItem, isVisible);
|
|
||||||
obs_sceneitem_release(sceneItem);
|
|
||||||
owner->SendOKResponse();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
owner->SendErrorResponse("specified scene item doesn't exist");
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_source_release(currentScene);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::HandleGetStreamingStatus(WSRequestHandler *owner) {
|
|
||||||
obs_data_t *data = obs_data_create();
|
|
||||||
obs_data_set_bool(data, "streaming", obs_frontend_streaming_active());
|
|
||||||
obs_data_set_bool(data, "recording", obs_frontend_recording_active());
|
|
||||||
obs_data_set_bool(data, "preview-only", false);
|
|
||||||
|
|
||||||
owner->SendOKResponse(data);
|
|
||||||
obs_data_release(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::HandleStartStopStreaming(WSRequestHandler *owner) {
|
|
||||||
if (obs_frontend_streaming_active()) {
|
|
||||||
obs_frontend_streaming_stop();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
obs_frontend_streaming_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
owner->SendOKResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::HandleStartStopRecording(WSRequestHandler *owner) {
|
|
||||||
if (obs_frontend_recording_active()) {
|
|
||||||
obs_frontend_recording_stop();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
obs_frontend_recording_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
owner->SendOKResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::HandleGetTransitionList(WSRequestHandler *owner) {
|
|
||||||
obs_source_t *current_transition = obs_frontend_get_current_transition();
|
|
||||||
obs_frontend_source_list transitionList = {};
|
|
||||||
obs_frontend_get_transitions(&transitionList);
|
|
||||||
|
|
||||||
obs_data_array_t* transitions = obs_data_array_create();
|
|
||||||
for (size_t i = 0; i < transitionList.sources.num; i++) {
|
|
||||||
obs_source_t* transition = transitionList.sources.array[i];
|
|
||||||
|
|
||||||
obs_data_t *obj = obs_data_create();
|
|
||||||
obs_data_set_string(obj, "name", obs_source_get_name(transition));
|
|
||||||
|
|
||||||
obs_data_array_push_back(transitions, obj);
|
|
||||||
obs_data_release(obj);
|
|
||||||
}
|
|
||||||
obs_frontend_source_list_free(&transitionList);
|
|
||||||
|
|
||||||
obs_data_t *response = obs_data_create();
|
|
||||||
obs_data_set_string(response, "current-transition", obs_source_get_name(current_transition));
|
|
||||||
obs_data_set_array(response, "transitions", transitions);
|
|
||||||
|
|
||||||
owner->SendOKResponse(response);
|
|
||||||
|
|
||||||
obs_data_release(response);
|
|
||||||
obs_data_array_release(transitions);
|
|
||||||
obs_source_release(current_transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::HandleGetCurrentTransition(WSRequestHandler *owner) {
|
|
||||||
obs_source_t *current_transition = obs_frontend_get_current_transition();
|
|
||||||
|
|
||||||
obs_data_t *response = obs_data_create();
|
|
||||||
obs_data_set_string(response, "name", obs_source_get_name(current_transition));
|
|
||||||
|
|
||||||
owner->SendOKResponse(response);
|
|
||||||
|
|
||||||
obs_data_release(response);
|
|
||||||
obs_source_release(current_transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::HandleSetCurrentTransition(WSRequestHandler *owner) {
|
|
||||||
const char *name = obs_data_get_string(owner->_requestData, "transition-name");
|
|
||||||
obs_source_t *transition = Utils::GetTransitionFromName(name);
|
|
||||||
|
|
||||||
if (transition) {
|
|
||||||
obs_frontend_set_current_transition(transition);
|
|
||||||
owner->SendOKResponse();
|
|
||||||
|
|
||||||
obs_source_release(transition);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
owner->SendErrorResponse("requested transition does not exist");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSRequestHandler::ErrNotImplemented(WSRequestHandler *owner) {
|
|
||||||
owner->SendErrorResponse("not implemented");
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
obs-websocket
|
|
||||||
Copyright (C) 2016 Stéphane Lepin <stephane.lepin@gmail.com>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WSREQUESTHANDLER_H
|
|
||||||
#define WSREQUESTHANDLER_H
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <set>
|
|
||||||
#include <QtWebSockets/QWebSocket>
|
|
||||||
#include <obs-frontend-api.h>
|
|
||||||
|
|
||||||
class WSRequestHandler : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit WSRequestHandler(QWebSocket *client);
|
|
||||||
~WSRequestHandler();
|
|
||||||
void sendTextMessage(QString textMessage);
|
|
||||||
bool isAuthenticated();
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
|
||||||
void processTextMessage(QString textMessage);
|
|
||||||
void socketDisconnected();
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void disconnected();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QWebSocket *_client;
|
|
||||||
bool _authenticated;
|
|
||||||
const char *_messageId;
|
|
||||||
const char *_requestType;
|
|
||||||
obs_data_t *_requestData;
|
|
||||||
|
|
||||||
std::map<std::string, void(*)(WSRequestHandler*)> messageMap;
|
|
||||||
std::set<std::string> authNotRequired;
|
|
||||||
|
|
||||||
void SendOKResponse(obs_data_t *additionalFields = NULL);
|
|
||||||
void SendErrorResponse(const char *errorMessage);
|
|
||||||
static void ErrNotImplemented(WSRequestHandler *owner);
|
|
||||||
|
|
||||||
static void HandleGetVersion(WSRequestHandler *owner);
|
|
||||||
static void HandleGetAuthRequired(WSRequestHandler *owner);
|
|
||||||
static void HandleAuthenticate(WSRequestHandler *owner);
|
|
||||||
|
|
||||||
static void HandleSetCurrentScene(WSRequestHandler *owner);
|
|
||||||
static void HandleGetCurrentScene(WSRequestHandler *owner);
|
|
||||||
static void HandleGetSceneList(WSRequestHandler *owner);
|
|
||||||
static void HandleSetSourceRender(WSRequestHandler *owner);
|
|
||||||
|
|
||||||
static void HandleGetStreamingStatus(WSRequestHandler *owner);
|
|
||||||
static void HandleStartStopStreaming(WSRequestHandler *owner);
|
|
||||||
static void HandleStartStopRecording(WSRequestHandler *owner);
|
|
||||||
|
|
||||||
static void HandleGetTransitionList(WSRequestHandler *owner);
|
|
||||||
static void HandleGetCurrentTransition(WSRequestHandler *owner);
|
|
||||||
static void HandleSetCurrentTransition(WSRequestHandler *owner);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // WSPROTOCOL_H
|
|
88
WSServer.cpp
88
WSServer.cpp
@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
obs-websocket
|
|
||||||
Copyright (C) 2016 Stéphane Lepin <stephane.lepin@gmail.com>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WSServer.h"
|
|
||||||
#include "WSRequestHandler.h"
|
|
||||||
#include "Config.h"
|
|
||||||
#include <QtWebSockets/QWebSocketServer>
|
|
||||||
#include <QtWebSockets/QWebSocket>
|
|
||||||
#include <QtCore/QDebug>
|
|
||||||
#include <QtCore/QThread>
|
|
||||||
#include <obs-frontend-api.h>
|
|
||||||
|
|
||||||
QT_USE_NAMESPACE
|
|
||||||
|
|
||||||
WSServer::WSServer(quint16 port, QObject *parent) :
|
|
||||||
QObject(parent),
|
|
||||||
_wsServer(Q_NULLPTR),
|
|
||||||
_clients()
|
|
||||||
{
|
|
||||||
_serverThread = new QThread();
|
|
||||||
_wsServer = new QWebSocketServer(
|
|
||||||
QStringLiteral("OBS Websocket API"),
|
|
||||||
QWebSocketServer::NonSecureMode,
|
|
||||||
this);
|
|
||||||
_wsServer->moveToThread(_serverThread);
|
|
||||||
_serverThread->start();
|
|
||||||
|
|
||||||
bool serverStarted = _wsServer->listen(QHostAddress::Any, port);
|
|
||||||
if (serverStarted) {
|
|
||||||
connect(_wsServer, &QWebSocketServer::newConnection, this, &WSServer::onNewConnection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WSServer::~WSServer()
|
|
||||||
{
|
|
||||||
_wsServer->close();
|
|
||||||
qDeleteAll(_clients.begin(), _clients.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSServer::broadcast(QString message)
|
|
||||||
{
|
|
||||||
Q_FOREACH(WSRequestHandler *pClient, _clients) {
|
|
||||||
if (Config::Current()->AuthRequired == true
|
|
||||||
&& pClient->isAuthenticated() == false) {
|
|
||||||
// Skip this client if unauthenticated
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
pClient->sendTextMessage(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSServer::onNewConnection()
|
|
||||||
{
|
|
||||||
QWebSocket *pSocket = _wsServer->nextPendingConnection();
|
|
||||||
|
|
||||||
if (pSocket) {
|
|
||||||
WSRequestHandler *pHandler = new WSRequestHandler(pSocket);
|
|
||||||
|
|
||||||
connect(pHandler, &WSRequestHandler::disconnected, this, &WSServer::socketDisconnected);
|
|
||||||
_clients << pHandler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WSServer::socketDisconnected()
|
|
||||||
{
|
|
||||||
WSRequestHandler *pClient = qobject_cast<WSRequestHandler *>(sender());
|
|
||||||
|
|
||||||
if (pClient) {
|
|
||||||
_clients.removeAll(pClient);
|
|
||||||
pClient->deleteLater();
|
|
||||||
}
|
|
||||||
}
|
|
49
WSServer.h
49
WSServer.h
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
obs-websocket
|
|
||||||
Copyright (C) 2016 Stéphane Lepin <stephane.lepin@gmail.com>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WSSERVER_H
|
|
||||||
#define WSSERVER_H
|
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
|
||||||
#include <QtCore/QList>
|
|
||||||
#include <QtCore/QByteArray>
|
|
||||||
#include "WSRequestHandler.h"
|
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QWebSocket)
|
|
||||||
|
|
||||||
class WSServer : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit WSServer(quint16 port, QObject *parent = Q_NULLPTR);
|
|
||||||
virtual ~WSServer();
|
|
||||||
void broadcast(QString message);
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
|
||||||
void onNewConnection();
|
|
||||||
void socketDisconnected();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QWebSocketServer *_wsServer;
|
|
||||||
QList<WSRequestHandler *> _clients;
|
|
||||||
QThread *_serverThread;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // WSSERVER_H
|
|
83
buildspec.json
Normal file
83
buildspec.json
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"obs-studio": {
|
||||||
|
"version": "28.0.0-beta2",
|
||||||
|
"repository": "https://github.com/obsproject/obs-studio.git",
|
||||||
|
"branch": "master",
|
||||||
|
"hash": "6c2860a4ecd69f95f6573b8917d77bbcea203669"
|
||||||
|
},
|
||||||
|
"prebuilt": {
|
||||||
|
"version": "2022-08-02",
|
||||||
|
"baseUrl": "https://github.com/obsproject/obs-deps/releases/download",
|
||||||
|
"label": "Pre-built obs-deps",
|
||||||
|
"hashes": {
|
||||||
|
"macos-x86_64": "7637e52305e6fc53014b5aabd583f1a4490b1d97450420e977cae9a336a29525",
|
||||||
|
"macos-arm64": "755e0fa69b17a3ae444e1befa9d91d77e3cafe628fbd1c6333686091826595cd",
|
||||||
|
"macos-universal": "de057e73e6fe0825664c258ca2dd6798c41ae580bf4d896e1647676a4941934a",
|
||||||
|
"windows-x64": "2192d8ce780c4281b807cd457994963669e5202659ecd92f19b54c3e7d0c1915",
|
||||||
|
"windows-x86": "9f8582ab5891b000869d6484ea591add9fbac9f1c91b56c7b85fdfd56a261c1b"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"qt5": {
|
||||||
|
"version": "2022-08-02",
|
||||||
|
"baseUrl": "https://github.com/obsproject/obs-deps/releases/download",
|
||||||
|
"label": "Pre-built Qt5",
|
||||||
|
"hashes": {
|
||||||
|
"macos-x86_64": "3d0381a52b0e4d49967936c4357f79ac711f43564329304a6db5c90edadd2697",
|
||||||
|
"macos-arm64": "f4b32548c0530f121956bf0a9a70c36ecbbfca81073d39c396a1759baf2a05c3",
|
||||||
|
"macos-universal": "9a6cf3b9a6c9efee6ba10df649202e8075e99f3c54ae88dc9a36dbc9d7471c1e",
|
||||||
|
"windows-x64": "6488a33a474f750d5a4a268a5e20c78bb40799d99136a1b7ce3365a843cb2fd7",
|
||||||
|
"windows-x86": "a916e09b0a874036801deab2c8a7ec14fdf5d268aa5511eac5bf40727e0c4e33"
|
||||||
|
},
|
||||||
|
"pdb-hashes": {
|
||||||
|
"windows-x64": "e0e5070143fcad9311a68ce5685d8ba8f34f581ed6942b7a92d360f94ca1ba11",
|
||||||
|
"windows-x86": "36642d1052aa461964f46c17610477b0d9b9defbe2d745ccaacb85f805c1bec2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"qt6": {
|
||||||
|
"version": "2022-08-02",
|
||||||
|
"baseUrl": "https://github.com/obsproject/obs-deps/releases/download",
|
||||||
|
"label": "Pre-built Qt6",
|
||||||
|
"hashes": {
|
||||||
|
"macos-x86_64": "a83f72a11023b03b6cb2dc365f0a66ad9df31163bbb4fe2df32d601856a9fad3",
|
||||||
|
"macos-arm64": "2f30af90c049670a5660656adbb440668aa1b0567f75a5f29e1def9108928403",
|
||||||
|
"macos-universal": "252e6684f43ab9c6f262c73af739e2296ce391b998da2c4ee04c254aaa07db18",
|
||||||
|
"windows-x64": "e5509b54196a3f935250cc4b9c54160c8e588fd0f92bc078a2a64f9d9e2e4e93",
|
||||||
|
"windows-x86": "24fc03bef153a0e027c1479e42eb08097a4ea1d70a4710825be0783d0626cb0d"
|
||||||
|
},
|
||||||
|
"pdb-hashes": {
|
||||||
|
"windows-x64": "60e5b1d2bc4d7c431bc05f14e3b1e85e088788c372fa85f58717cd6c49555a46",
|
||||||
|
"windows-x86": "f34d1a89fc85d92913bd6c7f75ec5c28471d74db708c98161100bc8b75f8fc63"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"platformConfig": {
|
||||||
|
"macos-x86_64": {
|
||||||
|
"qtVersion": 6,
|
||||||
|
"deploymentTarget": "10.15"
|
||||||
|
},
|
||||||
|
"macos-arm64": {
|
||||||
|
"qtVersion": 6,
|
||||||
|
"deploymentTarget": "11.0"
|
||||||
|
},
|
||||||
|
"macos-universal": {
|
||||||
|
"qtVersion": 6,
|
||||||
|
"deploymentTarget": "10.15"
|
||||||
|
},
|
||||||
|
"windows-x64": {
|
||||||
|
"qtVersion": 6,
|
||||||
|
"visualStudio": "Visual Studio 17 2022",
|
||||||
|
"platformSDK": "10.0.20348.0"
|
||||||
|
},
|
||||||
|
"windows-x86": {
|
||||||
|
"qtVersion": 6,
|
||||||
|
"visualStudio": "Visual Studio 17 2022",
|
||||||
|
"platformSDK": "10.0.20348.0"
|
||||||
|
},
|
||||||
|
"linux-x86_64": {
|
||||||
|
"qtVersion": 6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "obs-websocket-compat",
|
||||||
|
"version": "4.9.1"
|
||||||
|
}
|
506
cmake/ObsPluginHelpers.cmake
Normal file
506
cmake/ObsPluginHelpers.cmake
Normal file
@ -0,0 +1,506 @@
|
|||||||
|
if(POLICY CMP0087)
|
||||||
|
cmake_policy(SET CMP0087 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(OBS_STANDALONE_PLUGIN_DIR ${CMAKE_SOURCE_DIR}/release)
|
||||||
|
set(INCLUDED_LIBOBS_CMAKE_MODULES ON)
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
||||||
|
set(OS_MACOS ON)
|
||||||
|
set(OS_POSIX ON)
|
||||||
|
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD")
|
||||||
|
set(OS_POSIX ON)
|
||||||
|
string(TOUPPER "${CMAKE_SYSTEM_NAME}" _SYSTEM_NAME_U)
|
||||||
|
set(OS_${_SYSTEM_NAME_U} ON)
|
||||||
|
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||||
|
set(OS_WINDOWS ON)
|
||||||
|
set(OS_POSIX OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Old-Style plugin detected, find "modern" libobs variant instead and set global
|
||||||
|
# include directories to fix "bad" plugin behaviour
|
||||||
|
if(DEFINED LIBOBS_INCLUDE_DIR AND NOT TARGET OBS::libobs)
|
||||||
|
message(
|
||||||
|
DEPRECATION
|
||||||
|
"You are using an outdated method of adding 'libobs' to your project. Refer to the updated wiki on how to build and export 'libobs' and use it in your plugin projects."
|
||||||
|
)
|
||||||
|
find_package(libobs REQUIRED)
|
||||||
|
if(TARGET OBS::libobs)
|
||||||
|
set_target_properties(OBS::libobs PROPERTIES IMPORTED_GLOBAL TRUE)
|
||||||
|
message(STATUS "OBS: Using modern libobs target")
|
||||||
|
|
||||||
|
add_library(libobs ALIAS OBS::libobs)
|
||||||
|
if(OS_WINDOWS)
|
||||||
|
add_library(w32-pthreads ALIAS OBS::w32-pthreads)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND (OS_WINDOWS OR OS_MACOS))
|
||||||
|
set(CMAKE_INSTALL_PREFIX
|
||||||
|
${OBS_STANDALONE_PLUGIN_DIR}
|
||||||
|
CACHE STRING "Directory to install OBS plugin after building" FORCE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE
|
||||||
|
"RelWithDebInfo"
|
||||||
|
CACHE STRING
|
||||||
|
"OBS build type [Release, RelWithDebInfo, Debug, MinSizeRel]" FORCE)
|
||||||
|
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Release RelWithDebInfo
|
||||||
|
Debug MinSizeRel)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT QT_VERSION)
|
||||||
|
set(QT_VERSION
|
||||||
|
AUTO
|
||||||
|
CACHE STRING "OBS Qt version [AUTO, 5, 6]" FORCE)
|
||||||
|
set_property(CACHE QT_VERSION PROPERTY STRINGS AUTO 5 6)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
macro(find_qt)
|
||||||
|
set(multiValueArgs COMPONENTS COMPONENTS_WIN COMPONENTS_MAC COMPONENTS_LINUX)
|
||||||
|
cmake_parse_arguments(FIND_QT "" "${oneValueArgs}" "${multiValueArgs}"
|
||||||
|
${ARGN})
|
||||||
|
set(QT_NO_CREATE_VERSIONLESS_TARGETS ON)
|
||||||
|
find_package(
|
||||||
|
Qt5
|
||||||
|
COMPONENTS Core
|
||||||
|
QUIET)
|
||||||
|
find_package(
|
||||||
|
Qt6
|
||||||
|
COMPONENTS Core
|
||||||
|
QUIET)
|
||||||
|
|
||||||
|
if(NOT _QT_VERSION AND QT_VERSION STREQUAL AUTO)
|
||||||
|
if(TARGET Qt6::Core)
|
||||||
|
set(_QT_VERSION
|
||||||
|
6
|
||||||
|
CACHE INTERNAL "")
|
||||||
|
elseif(TARGET Qt5::Core)
|
||||||
|
set(_QT_VERSION
|
||||||
|
5
|
||||||
|
CACHE INTERNAL "")
|
||||||
|
endif()
|
||||||
|
message(STATUS "Qt version: ${_QT_VERSION}")
|
||||||
|
elseif(NOT _QT_VERSION)
|
||||||
|
if(TARGET Qt${QT_VERSION}::Core)
|
||||||
|
set(_QT_VERSION
|
||||||
|
${QT_VERSION}
|
||||||
|
CACHE INTERNAL "")
|
||||||
|
else()
|
||||||
|
if(QT_VERSION EQUAL 6)
|
||||||
|
set(FALLBACK_QT_VERSION 5)
|
||||||
|
else()
|
||||||
|
set(FALLBACK_QT_VERSION 6)
|
||||||
|
endif()
|
||||||
|
message(
|
||||||
|
WARNING
|
||||||
|
"Qt${QT_VERSION} was not found, falling back to Qt${FALLBACK_QT_VERSION}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(TARGET Qt${FALLBACK_QT_VERSION}::Core)
|
||||||
|
set(_QT_VERSION
|
||||||
|
${FALLBACK_QT_VERSION}
|
||||||
|
CACHE INTERNAL "")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
message(STATUS "Qt version: ${_QT_VERSION}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(QT_NO_CREATE_VERSIONLESS_TARGETS OFF)
|
||||||
|
|
||||||
|
if(NOT _QT_VERSION)
|
||||||
|
message(FATAL_ERROR "Neither Qt5 or Qt6 were found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(OS_WINDOWS)
|
||||||
|
find_package(
|
||||||
|
Qt${_QT_VERSION}
|
||||||
|
COMPONENTS ${FIND_QT_COMPONENTS} ${FIND_QT_COMPONENTS_WIN}
|
||||||
|
REQUIRED)
|
||||||
|
elseif(OS_MACOS)
|
||||||
|
find_package(
|
||||||
|
Qt${_QT_VERSION}
|
||||||
|
COMPONENTS ${FIND_QT_COMPONENTS} ${FIND_QT_COMPONENTS_MAC}
|
||||||
|
REQUIRED)
|
||||||
|
else()
|
||||||
|
find_package(
|
||||||
|
Qt${_QT_VERSION}
|
||||||
|
COMPONENTS ${FIND_QT_COMPONENTS} ${FIND_QT_COMPONENTS_LINUX}
|
||||||
|
REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND FIND_QT_COMPONENTS "Core")
|
||||||
|
|
||||||
|
if("Gui" IN_LIST FIND_QT_COMPONENTS_LINUX)
|
||||||
|
list(APPEND FIND_QT_COMPONENTS_LINUX "GuiPrivate")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(_COMPONENT IN LISTS FIND_QT_COMPONENTS FIND_QT_COMPONENTS_WIN
|
||||||
|
FIND_QT_COMPONENTS_MAC FIND_QT_COMPONENTS_LINUX)
|
||||||
|
if(NOT TARGET Qt::${_COMPONENT} AND TARGET Qt${_QT_VERSION}::${_COMPONENT})
|
||||||
|
|
||||||
|
add_library(Qt::${_COMPONENT} INTERFACE IMPORTED)
|
||||||
|
set_target_properties(
|
||||||
|
Qt::${_COMPONENT} PROPERTIES INTERFACE_LINK_LIBRARIES
|
||||||
|
"Qt${_QT_VERSION}::${_COMPONENT}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
file(RELATIVE_PATH RELATIVE_INSTALL_PATH ${CMAKE_SOURCE_DIR}
|
||||||
|
${CMAKE_INSTALL_PREFIX})
|
||||||
|
file(RELATIVE_PATH RELATIVE_BUILD_PATH ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
|
# Set up OS-specific environment and helper functions
|
||||||
|
if(OS_POSIX)
|
||||||
|
find_program(CCACHE_PROGRAM "ccache")
|
||||||
|
set(CCACHE_SUPPORT
|
||||||
|
ON
|
||||||
|
CACHE BOOL "Enable ccache support")
|
||||||
|
mark_as_advanced(CCACHE_PROGRAM)
|
||||||
|
if(CCACHE_PROGRAM AND CCACHE_SUPPORT)
|
||||||
|
set(CMAKE_CXX_COMPILER_LAUNCHER
|
||||||
|
${CCACHE_PROGRAM}
|
||||||
|
CACHE INTERNAL "")
|
||||||
|
set(CMAKE_C_COMPILER_LAUNCHER
|
||||||
|
${CCACHE_PROGRAM}
|
||||||
|
CACHE INTERNAL "")
|
||||||
|
set(CMAKE_OBJC_COMPILER_LAUNCHER
|
||||||
|
${CCACHE_PROGRAM}
|
||||||
|
CACHE INTERNAL "")
|
||||||
|
set(CMAKE_OBJCXX_COMPILER_LAUNCHER
|
||||||
|
${CCACHE_PROGRAM}
|
||||||
|
CACHE INTERNAL "")
|
||||||
|
set(CMAKE_CUDA_COMPILER_LAUNCHER
|
||||||
|
${CCACHE_PROGRAM}
|
||||||
|
CACHE INTERNAL "") # CMake 3.9+
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(OS_MACOS)
|
||||||
|
set(CMAKE_OSX_ARCHITECTURES
|
||||||
|
"x86_64"
|
||||||
|
CACHE STRING
|
||||||
|
"OBS build architecture for macOS - x86_64 required at least")
|
||||||
|
set_property(CACHE CMAKE_OSX_ARCHITECTURES PROPERTY STRINGS x86_64 arm64
|
||||||
|
"x86_64;arm64")
|
||||||
|
|
||||||
|
set(CMAKE_OSX_DEPLOYMENT_TARGET
|
||||||
|
"10.15"
|
||||||
|
CACHE STRING "OBS deployment target for macOS - 10.15+ required")
|
||||||
|
set_property(CACHE CMAKE_OSX_DEPLOYMENT_TARGET PROPERTY STRINGS 10.15 11.0
|
||||||
|
12.0 13.0)
|
||||||
|
|
||||||
|
set(OBS_BUNDLE_CODESIGN_IDENTITY
|
||||||
|
"-"
|
||||||
|
CACHE STRING "OBS code signing identity for macOS")
|
||||||
|
set(OBS_CODESIGN_ENTITLEMENTS
|
||||||
|
${CMAKE_SOURCE_DIR}/cmake/bundle/macos/entitlements.plist
|
||||||
|
CACHE INTERNAL "Path to codesign entitlements plist")
|
||||||
|
set(OBS_CODESIGN_LINKER
|
||||||
|
ON
|
||||||
|
CACHE BOOL "Enable linker code-signing on macOS (macOS 11+ required)")
|
||||||
|
|
||||||
|
# Xcode configuration
|
||||||
|
if(XCODE)
|
||||||
|
# Tell Xcode to pretend the linker signed binaries so that editing with
|
||||||
|
# install_name_tool preserves ad-hoc signatures. This option is supported by
|
||||||
|
# codesign on macOS 11 or higher. See CMake Issue 21854:
|
||||||
|
# https://gitlab.kitware.com/cmake/cmake/-/issues/21854
|
||||||
|
|
||||||
|
set(CMAKE_XCODE_GENERATE_SCHEME ON)
|
||||||
|
if(OBS_CODESIGN_LINKER)
|
||||||
|
set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "-o linker-signed")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Set default options for bundling on macOS
|
||||||
|
set(CMAKE_MACOSX_RPATH ON)
|
||||||
|
set(CMAKE_SKIP_BUILD_RPATH OFF)
|
||||||
|
set(CMAKE_BUILD_WITH_INSTALL_RPATH OFF)
|
||||||
|
set(CMAKE_INSTALL_RPATH "@executable_path/../Frameworks/")
|
||||||
|
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH OFF)
|
||||||
|
|
||||||
|
function(setup_plugin_target target)
|
||||||
|
if(NOT DEFINED MACOSX_PLUGIN_GUI_IDENTIFIER)
|
||||||
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"No 'MACOSX_PLUGIN_GUI_IDENTIFIER' set, but is required to build plugin bundles on macOS - example: 'com.yourname.pluginname'"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED MACOSX_PLUGIN_BUNDLE_VERSION)
|
||||||
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"No 'MACOSX_PLUGIN_BUNDLE_VERSION' set, but is required to build plugin bundles on macOS - example: '25'"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED MACOSX_PLUGIN_SHORT_VERSION_STRING)
|
||||||
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"No 'MACOSX_PLUGIN_SHORT_VERSION_STRING' set, but is required to build plugin bundles on macOS - example: '1.0.2'"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(MACOSX_PLUGIN_BUNDLE_NAME
|
||||||
|
"${target}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(MACOSX_PLUGIN_BUNDLE_VERSION
|
||||||
|
"${MACOSX_BUNDLE_BUNDLE_VERSION}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(MACOSX_PLUGIN_SHORT_VERSION_STRING
|
||||||
|
"${MACOSX_BUNDLE_SHORT_VERSION_STRING}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(MACOSX_PLUGIN_EXECUTABLE_NAME
|
||||||
|
"${target}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(MACOSX_PLUGIN_BUNDLE_TYPE
|
||||||
|
"BNDL"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS ${target}
|
||||||
|
LIBRARY DESTINATION "."
|
||||||
|
COMPONENT obs_plugins
|
||||||
|
NAMELINK_COMPONENT ${target}_Development)
|
||||||
|
|
||||||
|
if(${QT_VERSION} EQUAL 5)
|
||||||
|
set(_QT_FW_VERSION "${QT_VERSION}")
|
||||||
|
else()
|
||||||
|
set(_QT_FW_VERSION "A")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_COMMAND
|
||||||
|
"${CMAKE_INSTALL_NAME_TOOL} \\
|
||||||
|
-change ${CMAKE_PREFIX_PATH}/lib/QtWidgets.framework/Versions/${QT_VERSION}/QtWidgets @rpath/QtWidgets.framework/Versions/${_QT_FW_VERSION}/QtWidgets \\
|
||||||
|
-change ${CMAKE_PREFIX_PATH}/lib/QtCore.framework/Versions/${QT_VERSION}/QtCore @rpath/QtCore.framework/Versions/${_QT_FW_VERSION}/QtCore \\
|
||||||
|
-change ${CMAKE_PREFIX_PATH}/lib/QtGui.framework/Versions/${QT_VERSION}/QtGui @rpath/QtGui.framework/Versions/${_QT_FW_VERSION}/QtGui \\
|
||||||
|
\\\"\${CMAKE_INSTALL_PREFIX}/${target}.plugin/Contents/MacOS/${target}\\\""
|
||||||
|
)
|
||||||
|
install(CODE "execute_process(COMMAND /bin/sh -c \"${_COMMAND}\")"
|
||||||
|
COMPONENT obs_plugins)
|
||||||
|
unset(_QT_FW_VERSION)
|
||||||
|
|
||||||
|
if(NOT XCODE)
|
||||||
|
set(_COMMAND
|
||||||
|
"/usr/bin/codesign --force \\
|
||||||
|
--sign \\\"${OBS_BUNDLE_CODESIGN_IDENTITY}\\\" \\
|
||||||
|
--options runtime \\
|
||||||
|
--entitlements \\\"${CMAKE_CURRENT_FUNCTION_LIST_DIR}/bundle/macOS/entitlements.plist\\\" \\
|
||||||
|
\\\"\${CMAKE_INSTALL_PREFIX}/${target}.plugin\\\"")
|
||||||
|
install(CODE "execute_process(COMMAND /bin/sh -c \"${_COMMAND}\")"
|
||||||
|
COMPONENT obs_plugins)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_target_properties(
|
||||||
|
${target}
|
||||||
|
PROPERTIES
|
||||||
|
BUNDLE ON
|
||||||
|
BUNDLE_EXTENSION "plugin"
|
||||||
|
OUTPUT_NAME ${target}
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST
|
||||||
|
"${CMAKE_CURRENT_FUNCTION_LIST_DIR}/bundle/macOS/Plugin-Info.plist.in"
|
||||||
|
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER
|
||||||
|
"${MACOSX_PLUGIN_GUI_IDENTIFIER}"
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${OBS_BUNDLE_CODESIGN_IDENTITY}"
|
||||||
|
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS
|
||||||
|
"${CMAKE_CURRENT_FUNCTION_LIST_DIR}/bundle/macOS/entitlements.plist")
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${target}
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND
|
||||||
|
/bin/sh -c
|
||||||
|
"codesign --force --sign \"-\" $<$<BOOL:${OBS_CODESIGN_LINKER}>:--options linker-signed >\"$<TARGET_BUNDLE_DIR:${target}>\""
|
||||||
|
COMMENT "Codesigning ${target}"
|
||||||
|
VERBATIM)
|
||||||
|
|
||||||
|
install_bundle_resources(${target})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(install_bundle_resources target)
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/data)
|
||||||
|
file(GLOB_RECURSE _DATA_FILES "${CMAKE_CURRENT_SOURCE_DIR}/data/*")
|
||||||
|
foreach(_DATA_FILE IN LISTS _DATA_FILES)
|
||||||
|
file(RELATIVE_PATH _RELATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/data/
|
||||||
|
${_DATA_FILE})
|
||||||
|
get_filename_component(_RELATIVE_PATH ${_RELATIVE_PATH} PATH)
|
||||||
|
target_sources(${target} PRIVATE ${_DATA_FILE})
|
||||||
|
set_source_files_properties(
|
||||||
|
${_DATA_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION
|
||||||
|
Resources/${_RELATIVE_PATH})
|
||||||
|
string(REPLACE "\\" "\\\\" _GROUP_NAME ${_RELATIVE_PATH})
|
||||||
|
source_group("Resources\\${_GROUP_NAME}" FILES ${_DATA_FILE})
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
else()
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(_ARCH_SUFFIX 64)
|
||||||
|
else()
|
||||||
|
set(_ARCH_SUFFIX 32)
|
||||||
|
endif()
|
||||||
|
set(OBS_OUTPUT_DIR ${CMAKE_BINARY_DIR}/rundir)
|
||||||
|
|
||||||
|
if(OS_POSIX)
|
||||||
|
option(LINUX_PORTABLE "Build portable version (Linux)" ON)
|
||||||
|
if(NOT LINUX_PORTABLE)
|
||||||
|
set(OBS_LIBRARY_DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||||
|
set(OBS_PLUGIN_DESTINATION ${OBS_LIBRARY_DESTINATION}/obs-plugins)
|
||||||
|
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib)
|
||||||
|
set(OBS_DATA_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/obs)
|
||||||
|
else()
|
||||||
|
set(OBS_LIBRARY_DESTINATION bin/${_ARCH_SUFFIX}bit)
|
||||||
|
set(OBS_PLUGIN_DESTINATION obs-plugins/${_ARCH_SUFFIX}bit)
|
||||||
|
set(CMAKE_INSTALL_RPATH
|
||||||
|
"$ORIGIN/" "${CMAKE_INSTALL_PREFIX}/${OBS_LIBRARY_DESTINATION}")
|
||||||
|
set(OBS_DATA_DESTINATION "data")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(OS_LINUX)
|
||||||
|
set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${LINUX_MAINTAINER_EMAIL}")
|
||||||
|
set(CPACK_PACKAGE_VERSION "${CMAKE_PROJECT_VERSION}")
|
||||||
|
set(CPACK_PACKAGE_FILE_NAME
|
||||||
|
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-linux-x86_64")
|
||||||
|
|
||||||
|
set(CPACK_GENERATOR "DEB")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_DEPENDS
|
||||||
|
"obs-studio (>= 27.0.0), libqt5core5a (>= 5.9.0~beta), libqt5gui5 (>= 5.3.0), libqt5widgets5 (>= 5.7.0)"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CPACK_OUTPUT_FILE_PREFIX ${CMAKE_SOURCE_DIR}/release)
|
||||||
|
|
||||||
|
if(NOT LINUX_PORTABLE)
|
||||||
|
set(CPACK_SET_DESTDIR ON)
|
||||||
|
endif()
|
||||||
|
include(CPack)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(OBS_LIBRARY_DESTINATION "bin/${_ARCH_SUFFIX}bit")
|
||||||
|
set(OBS_LIBRARY32_DESTINATION "bin/32bit")
|
||||||
|
set(OBS_LIBRARY64_DESTINATION "bin/64bit")
|
||||||
|
set(OBS_PLUGIN_DESTINATION "obs-plugins/${_ARCH_SUFFIX}bit")
|
||||||
|
set(OBS_PLUGIN32_DESTINATION "obs-plugins/32bit")
|
||||||
|
set(OBS_PLUGIN64_DESTINATION "obs-plugins/64bit")
|
||||||
|
|
||||||
|
set(OBS_DATA_DESTINATION "data")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
function(setup_plugin_target target)
|
||||||
|
set_target_properties(${target} PROPERTIES PREFIX "")
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS ${target}
|
||||||
|
RUNTIME DESTINATION "${OBS_PLUGIN_DESTINATION}"
|
||||||
|
COMPONENT ${target}_Runtime
|
||||||
|
LIBRARY DESTINATION "${OBS_PLUGIN_DESTINATION}"
|
||||||
|
COMPONENT ${target}_Runtime
|
||||||
|
NAMELINK_COMPONENT ${target}_Development)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES $<TARGET_FILE:${target}>
|
||||||
|
DESTINATION $<CONFIG>/${OBS_PLUGIN_DESTINATION}
|
||||||
|
COMPONENT obs_rundir
|
||||||
|
EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
if(OS_WINDOWS)
|
||||||
|
install(
|
||||||
|
FILES $<TARGET_PDB_FILE:${target}>
|
||||||
|
CONFIGURATIONS "RelWithDebInfo" "Debug"
|
||||||
|
DESTINATION ${OBS_PLUGIN_DESTINATION}
|
||||||
|
COMPONENT ${target}_Runtime
|
||||||
|
OPTIONAL)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES $<TARGET_PDB_FILE:${target}>
|
||||||
|
CONFIGURATIONS "RelWithDebInfo" "Debug"
|
||||||
|
DESTINATION $<CONFIG>/${OBS_PLUGIN_DESTINATION}
|
||||||
|
COMPONENT obs_rundir
|
||||||
|
OPTIONAL EXCLUDE_FROM_ALL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
target_link_options(
|
||||||
|
${target}
|
||||||
|
PRIVATE
|
||||||
|
"LINKER:/OPT:REF"
|
||||||
|
"$<$<NOT:$<EQUAL:${CMAKE_SIZEOF_VOID_P},8>>:LINKER\:/SAFESEH\:NO>"
|
||||||
|
"$<$<CONFIG:DEBUG>:LINKER\:/INCREMENTAL:NO>"
|
||||||
|
"$<$<CONFIG:RELWITHDEBINFO>:LINKER\:/INCREMENTAL:NO>")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
setup_target_resources(${target} obs-plugins/${target})
|
||||||
|
|
||||||
|
if(OS_WINDOWS AND DEFINED OBS_BUILD_DIR)
|
||||||
|
setup_target_for_testing(${target} obs-plugins/${target})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${target}
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND
|
||||||
|
"${CMAKE_COMMAND}" -DCMAKE_INSTALL_PREFIX=${OBS_OUTPUT_DIR}
|
||||||
|
-DCMAKE_INSTALL_COMPONENT=obs_rundir
|
||||||
|
-DCMAKE_INSTALL_CONFIG_NAME=$<CONFIG> -P
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake
|
||||||
|
COMMENT "Installing to plugin rundir"
|
||||||
|
VERBATIM)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(setup_target_resources target destination)
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/data)
|
||||||
|
install(
|
||||||
|
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/
|
||||||
|
DESTINATION ${OBS_DATA_DESTINATION}/${destination}
|
||||||
|
USE_SOURCE_PERMISSIONS
|
||||||
|
COMPONENT obs_plugins)
|
||||||
|
|
||||||
|
install(
|
||||||
|
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data
|
||||||
|
DESTINATION $<CONFIG>/${OBS_DATA_DESTINATION}/${destination}
|
||||||
|
USE_SOURCE_PERMISSIONS
|
||||||
|
COMPONENT obs_rundir
|
||||||
|
EXCLUDE_FROM_ALL)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
if(OS_WINDOWS)
|
||||||
|
function(setup_target_for_testing target destination)
|
||||||
|
install(
|
||||||
|
FILES $<TARGET_FILE:${target}>
|
||||||
|
DESTINATION $<CONFIG>/${OBS_PLUGIN_DESTINATION}
|
||||||
|
COMPONENT obs_testing
|
||||||
|
EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES $<TARGET_PDB_FILE:${target}>
|
||||||
|
CONFIGURATIONS "RelWithDebInfo" "Debug"
|
||||||
|
DESTINATION $<CONFIG>/${OBS_PLUGIN_DESTINATION}
|
||||||
|
COMPONENT obs_testing
|
||||||
|
OPTIONAL EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
install(
|
||||||
|
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/
|
||||||
|
DESTINATION $<CONFIG>/${OBS_DATA_DESTINATION}/${destination}
|
||||||
|
USE_SOURCE_PERMISSIONS
|
||||||
|
COMPONENT obs_testing
|
||||||
|
EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${target}
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND
|
||||||
|
"${CMAKE_COMMAND}" -DCMAKE_INSTALL_PREFIX=${OBS_BUILD_DIR}/rundir
|
||||||
|
-DCMAKE_INSTALL_COMPONENT=obs_testing
|
||||||
|
-DCMAKE_INSTALL_CONFIG_NAME=$<CONFIG> -P
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake
|
||||||
|
COMMENT "Installing to OBS test directory"
|
||||||
|
VERBATIM)
|
||||||
|
endfunction()
|
||||||
|
endif()
|
||||||
|
endif()
|
26
cmake/bundle/macos/Plugin-Info.plist.in
Normal file
26
cmake/bundle/macos/Plugin-Info.plist.in
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>${MACOSX_PLUGIN_BUNDLE_NAME}</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>${MACOSX_PLUGIN_GUI_IDENTIFIER}</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>${MACOSX_PLUGIN_BUNDLE_VERSION}</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>${MACOSX_PLUGIN_SHORT_VERSION_STRING}</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>${MACOSX_PLUGIN_EXECUTABLE_NAME}</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>${MACOSX_PLUGIN_BUNDLE_TYPE}</string>
|
||||||
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
|
<array>
|
||||||
|
<string>MacOSX</string>
|
||||||
|
</array>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>10.13</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
17
cmake/bundle/macos/entitlements.plist
Normal file
17
cmake/bundle/macos/entitlements.plist
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<!--?xml version="1.0" encoding="UTF-8"?-->
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.device.camera</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.device.audio-input</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.cs.disable-library-validation</key>
|
||||||
|
<true/>
|
||||||
|
<!-- Allows @executable_path to load libaries from within the .app bundle. -->
|
||||||
|
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
920
cmake/bundle/macos/installer-macos.pkgproj.in
Normal file
920
cmake/bundle/macos/installer-macos.pkgproj.in
Normal file
@ -0,0 +1,920 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>PACKAGES</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>MUST-CLOSE-APPLICATION-ITEMS</key>
|
||||||
|
<array/>
|
||||||
|
<key>MUST-CLOSE-APPLICATIONS</key>
|
||||||
|
<false/>
|
||||||
|
<key>PACKAGE_FILES</key>
|
||||||
|
<dict>
|
||||||
|
<key>DEFAULT_INSTALL_LOCATION</key>
|
||||||
|
<string>/</string>
|
||||||
|
<key>HIERARCHY</key>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>80</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Applications</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>509</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>BUNDLE_CAN_DOWNGRADE</key>
|
||||||
|
<false/>
|
||||||
|
<key>BUNDLE_POSTINSTALL_PATH</key>
|
||||||
|
<dict>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<key>BUNDLE_PREINSTALL_PATH</key>
|
||||||
|
<dict>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>80</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>../@RELATIVE_INSTALL_PATH@/@CMAKE_PROJECT_NAME@.plugin</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>3</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>80</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>plugins</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>2</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>509</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>2</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>80</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>obs-studio</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>2</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>509</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>2</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>80</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Application Support</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Automator</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Documentation</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Extensions</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Filesystems</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Frameworks</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Input Methods</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Internet Plug-Ins</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>LaunchAgents</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>LaunchDaemons</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>PreferencePanes</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Preferences</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>80</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Printers</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>PrivilegedHelperTools</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>1005</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>QuickLook</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>QuickTime</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Screen Savers</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Scripts</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Services</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Widgets</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Library</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Shared</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>1023</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>80</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>Users</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>GID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>/</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PERMISSIONS</key>
|
||||||
|
<integer>493</integer>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>UID</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<key>PAYLOAD_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>PRESERVE_EXTENDED_ATTRIBUTES</key>
|
||||||
|
<false/>
|
||||||
|
<key>SHOW_INVISIBLE</key>
|
||||||
|
<false/>
|
||||||
|
<key>SPLIT_FORKS</key>
|
||||||
|
<true/>
|
||||||
|
<key>TREAT_MISSING_FILES_AS_WARNING</key>
|
||||||
|
<false/>
|
||||||
|
<key>VERSION</key>
|
||||||
|
<integer>5</integer>
|
||||||
|
</dict>
|
||||||
|
<key>PACKAGE_SCRIPTS</key>
|
||||||
|
<dict>
|
||||||
|
<key>POSTINSTALL_PATH</key>
|
||||||
|
<dict>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<key>PREINSTALL_PATH</key>
|
||||||
|
<dict>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<key>RESOURCES</key>
|
||||||
|
<array/>
|
||||||
|
</dict>
|
||||||
|
<key>PACKAGE_SETTINGS</key>
|
||||||
|
<dict>
|
||||||
|
<key>AUTHENTICATION</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>CONCLUSION_ACTION</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>FOLLOW_SYMBOLIC_LINKS</key>
|
||||||
|
<false/>
|
||||||
|
<key>IDENTIFIER</key>
|
||||||
|
<string>@MACOS_BUNDLEID@</string>
|
||||||
|
<key>LOCATION</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>NAME</key>
|
||||||
|
<string>@CMAKE_PROJECT_NAME@</string>
|
||||||
|
<key>OVERWRITE_PERMISSIONS</key>
|
||||||
|
<false/>
|
||||||
|
<key>PAYLOAD_SIZE</key>
|
||||||
|
<integer>-1</integer>
|
||||||
|
<key>REFERENCE_PATH</key>
|
||||||
|
<string></string>
|
||||||
|
<key>RELOCATABLE</key>
|
||||||
|
<false/>
|
||||||
|
<key>USE_HFS+_COMPRESSION</key>
|
||||||
|
<false/>
|
||||||
|
<key>VERSION</key>
|
||||||
|
<string>@CMAKE_PROJECT_VERSION@</string>
|
||||||
|
</dict>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>UUID</key>
|
||||||
|
<string>0B7A74BC-65CF-4FF1-AC34-5C743E8A48F5</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>PROJECT</key>
|
||||||
|
<dict>
|
||||||
|
<key>PROJECT_COMMENTS</key>
|
||||||
|
<dict>
|
||||||
|
<key>NOTES</key>
|
||||||
|
<data>
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>PROJECT_PRESENTATION</key>
|
||||||
|
<dict>
|
||||||
|
<key>BACKGROUND</key>
|
||||||
|
<dict>
|
||||||
|
<key>APPAREANCES</key>
|
||||||
|
<dict>
|
||||||
|
<key>DARK_AQUA</key>
|
||||||
|
<dict/>
|
||||||
|
<key>LIGHT_AQUA</key>
|
||||||
|
<dict/>
|
||||||
|
</dict>
|
||||||
|
<key>SHARED_SETTINGS_FOR_ALL_APPAREANCES</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<key>INSTALLATION TYPE</key>
|
||||||
|
<dict>
|
||||||
|
<key>HIERARCHIES</key>
|
||||||
|
<dict>
|
||||||
|
<key>INSTALLER</key>
|
||||||
|
<dict>
|
||||||
|
<key>LIST</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CHILDREN</key>
|
||||||
|
<array/>
|
||||||
|
<key>DESCRIPTION</key>
|
||||||
|
<array/>
|
||||||
|
<key>OPTIONS</key>
|
||||||
|
<dict>
|
||||||
|
<key>HIDDEN</key>
|
||||||
|
<false/>
|
||||||
|
<key>STATE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
</dict>
|
||||||
|
<key>PACKAGE_UUID</key>
|
||||||
|
<string>0B7A74BC-65CF-4FF1-AC34-5C743E8A48F5</string>
|
||||||
|
<key>TITLE</key>
|
||||||
|
<array/>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>UUID</key>
|
||||||
|
<string>52B6084A-F58D-45C3-BE37-76AD45F16072</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>REMOVED</key>
|
||||||
|
<dict/>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>MODE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<key>INSTALLATION_STEPS</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
|
||||||
|
<string>ICPresentationViewIntroductionController</string>
|
||||||
|
<key>INSTALLER_PLUGIN</key>
|
||||||
|
<string>Introduction</string>
|
||||||
|
<key>LIST_TITLE_KEY</key>
|
||||||
|
<string>InstallerSectionTitle</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
|
||||||
|
<string>ICPresentationViewReadMeController</string>
|
||||||
|
<key>INSTALLER_PLUGIN</key>
|
||||||
|
<string>ReadMe</string>
|
||||||
|
<key>LIST_TITLE_KEY</key>
|
||||||
|
<string>InstallerSectionTitle</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
|
||||||
|
<string>ICPresentationViewLicenseController</string>
|
||||||
|
<key>INSTALLER_PLUGIN</key>
|
||||||
|
<string>License</string>
|
||||||
|
<key>LIST_TITLE_KEY</key>
|
||||||
|
<string>InstallerSectionTitle</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
|
||||||
|
<string>ICPresentationViewDestinationSelectController</string>
|
||||||
|
<key>INSTALLER_PLUGIN</key>
|
||||||
|
<string>TargetSelect</string>
|
||||||
|
<key>LIST_TITLE_KEY</key>
|
||||||
|
<string>InstallerSectionTitle</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
|
||||||
|
<string>ICPresentationViewInstallationTypeController</string>
|
||||||
|
<key>INSTALLER_PLUGIN</key>
|
||||||
|
<string>PackageSelection</string>
|
||||||
|
<key>LIST_TITLE_KEY</key>
|
||||||
|
<string>InstallerSectionTitle</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
|
||||||
|
<string>ICPresentationViewInstallationController</string>
|
||||||
|
<key>INSTALLER_PLUGIN</key>
|
||||||
|
<string>Install</string>
|
||||||
|
<key>LIST_TITLE_KEY</key>
|
||||||
|
<string>InstallerSectionTitle</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
|
||||||
|
<string>ICPresentationViewSummaryController</string>
|
||||||
|
<key>INSTALLER_PLUGIN</key>
|
||||||
|
<string>Summary</string>
|
||||||
|
<key>LIST_TITLE_KEY</key>
|
||||||
|
<string>InstallerSectionTitle</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>INTRODUCTION</key>
|
||||||
|
<dict>
|
||||||
|
<key>LOCALIZATIONS</key>
|
||||||
|
<array/>
|
||||||
|
</dict>
|
||||||
|
<key>LICENSE</key>
|
||||||
|
<dict>
|
||||||
|
<key>LOCALIZATIONS</key>
|
||||||
|
<array/>
|
||||||
|
<key>MODE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<key>README</key>
|
||||||
|
<dict>
|
||||||
|
<key>LOCALIZATIONS</key>
|
||||||
|
<array/>
|
||||||
|
</dict>
|
||||||
|
<key>SUMMARY</key>
|
||||||
|
<dict>
|
||||||
|
<key>LOCALIZATIONS</key>
|
||||||
|
<array/>
|
||||||
|
</dict>
|
||||||
|
<key>TITLE</key>
|
||||||
|
<dict>
|
||||||
|
<key>LOCALIZATIONS</key>
|
||||||
|
<array/>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>PROJECT_REQUIREMENTS</key>
|
||||||
|
<dict>
|
||||||
|
<key>LIST</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>BEHAVIOR</key>
|
||||||
|
<integer>3</integer>
|
||||||
|
<key>DICTIONARY</key>
|
||||||
|
<dict>
|
||||||
|
<key>IC_REQUIREMENT_OS_DISK_TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>IC_REQUIREMENT_OS_DISTRIBUTION_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>IC_REQUIREMENT_OS_MINIMUM_VERSION</key>
|
||||||
|
<integer>101300</integer>
|
||||||
|
</dict>
|
||||||
|
<key>IC_REQUIREMENT_CHECK_TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>IDENTIFIER</key>
|
||||||
|
<string>fr.whitebox.Packages.requirement.os</string>
|
||||||
|
<key>MESSAGE</key>
|
||||||
|
<array/>
|
||||||
|
<key>NAME</key>
|
||||||
|
<string>Operating System</string>
|
||||||
|
<key>STATE</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>RESOURCES</key>
|
||||||
|
<array/>
|
||||||
|
<key>ROOT_VOLUME_ONLY</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<key>PROJECT_SETTINGS</key>
|
||||||
|
<dict>
|
||||||
|
<key>ADVANCED_OPTIONS</key>
|
||||||
|
<dict>
|
||||||
|
<key>installer-script.domains:enable_currentUserHome</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
</dict>
|
||||||
|
<key>BUILD_FORMAT</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>BUILD_PATH</key>
|
||||||
|
<dict>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>../@RELATIVE_BUILD_PATH@</string>
|
||||||
|
<key>PATH_TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
</dict>
|
||||||
|
<key>EXCLUDED_FILES</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>PATTERNS_ARRAY</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>REGULAR_EXPRESSION</key>
|
||||||
|
<false/>
|
||||||
|
<key>STRING</key>
|
||||||
|
<string>.DS_Store</string>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>PROTECTED</key>
|
||||||
|
<true/>
|
||||||
|
<key>PROXY_NAME</key>
|
||||||
|
<string>Remove .DS_Store files</string>
|
||||||
|
<key>PROXY_TOOLTIP</key>
|
||||||
|
<string>Remove ".DS_Store" files created by the Finder.</string>
|
||||||
|
<key>STATE</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>PATTERNS_ARRAY</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>REGULAR_EXPRESSION</key>
|
||||||
|
<false/>
|
||||||
|
<key>STRING</key>
|
||||||
|
<string>.pbdevelopment</string>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>PROTECTED</key>
|
||||||
|
<true/>
|
||||||
|
<key>PROXY_NAME</key>
|
||||||
|
<string>Remove .pbdevelopment files</string>
|
||||||
|
<key>PROXY_TOOLTIP</key>
|
||||||
|
<string>Remove ".pbdevelopment" files created by ProjectBuilder or Xcode.</string>
|
||||||
|
<key>STATE</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>PATTERNS_ARRAY</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>REGULAR_EXPRESSION</key>
|
||||||
|
<false/>
|
||||||
|
<key>STRING</key>
|
||||||
|
<string>CVS</string>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>REGULAR_EXPRESSION</key>
|
||||||
|
<false/>
|
||||||
|
<key>STRING</key>
|
||||||
|
<string>.cvsignore</string>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>REGULAR_EXPRESSION</key>
|
||||||
|
<false/>
|
||||||
|
<key>STRING</key>
|
||||||
|
<string>.cvspass</string>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>REGULAR_EXPRESSION</key>
|
||||||
|
<false/>
|
||||||
|
<key>STRING</key>
|
||||||
|
<string>.svn</string>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>REGULAR_EXPRESSION</key>
|
||||||
|
<false/>
|
||||||
|
<key>STRING</key>
|
||||||
|
<string>.git</string>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>REGULAR_EXPRESSION</key>
|
||||||
|
<false/>
|
||||||
|
<key>STRING</key>
|
||||||
|
<string>.gitignore</string>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>PROTECTED</key>
|
||||||
|
<true/>
|
||||||
|
<key>PROXY_NAME</key>
|
||||||
|
<string>Remove SCM metadata</string>
|
||||||
|
<key>PROXY_TOOLTIP</key>
|
||||||
|
<string>Remove helper files and folders used by the CVS, SVN or Git Source Code Management systems.</string>
|
||||||
|
<key>STATE</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>PATTERNS_ARRAY</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>REGULAR_EXPRESSION</key>
|
||||||
|
<false/>
|
||||||
|
<key>STRING</key>
|
||||||
|
<string>classes.nib</string>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>REGULAR_EXPRESSION</key>
|
||||||
|
<false/>
|
||||||
|
<key>STRING</key>
|
||||||
|
<string>designable.db</string>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>REGULAR_EXPRESSION</key>
|
||||||
|
<false/>
|
||||||
|
<key>STRING</key>
|
||||||
|
<string>info.nib</string>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>PROTECTED</key>
|
||||||
|
<true/>
|
||||||
|
<key>PROXY_NAME</key>
|
||||||
|
<string>Optimize nib files</string>
|
||||||
|
<key>PROXY_TOOLTIP</key>
|
||||||
|
<string>Remove "classes.nib", "info.nib" and "designable.nib" files within .nib bundles.</string>
|
||||||
|
<key>STATE</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>PATTERNS_ARRAY</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>REGULAR_EXPRESSION</key>
|
||||||
|
<false/>
|
||||||
|
<key>STRING</key>
|
||||||
|
<string>Resources Disabled</string>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>PROTECTED</key>
|
||||||
|
<true/>
|
||||||
|
<key>PROXY_NAME</key>
|
||||||
|
<string>Remove Resources Disabled folders</string>
|
||||||
|
<key>PROXY_TOOLTIP</key>
|
||||||
|
<string>Remove "Resources Disabled" folders.</string>
|
||||||
|
<key>STATE</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>SEPARATOR</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>NAME</key>
|
||||||
|
<string>@CMAKE_PROJECT_NAME@</string>
|
||||||
|
<key>PAYLOAD_ONLY</key>
|
||||||
|
<false/>
|
||||||
|
<key>TREAT_MISSING_PRESENTATION_DOCUMENTS_AS_WARNING</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>TYPE</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>VERSION</key>
|
||||||
|
<integer>2</integer>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
63
cmake/bundle/windows/installer-Windows.iss.in
Normal file
63
cmake/bundle/windows/installer-Windows.iss.in
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#define MyAppName "@CMAKE_PROJECT_NAME@"
|
||||||
|
#define MyAppVersion "@CMAKE_PROJECT_VERSION@"
|
||||||
|
#define MyAppPublisher "@PLUGIN_AUTHOR@"
|
||||||
|
#define MyAppURL "https://obsproject.com"
|
||||||
|
|
||||||
|
[Setup]
|
||||||
|
; NOTE: The value of AppId uniquely identifies this application.
|
||||||
|
; Do not use the same AppId value in installers for other applications.
|
||||||
|
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
||||||
|
AppId={{CD703FE5-1F2C-4837-BD3D-DD840D83C3E3}
|
||||||
|
AppName={#MyAppName}
|
||||||
|
AppVersion={#MyAppVersion}
|
||||||
|
AppPublisher={#MyAppPublisher}
|
||||||
|
AppPublisherURL={#MyAppURL}
|
||||||
|
AppSupportURL={#MyAppURL}
|
||||||
|
AppUpdatesURL={#MyAppURL}
|
||||||
|
DefaultDirName={code:GetDirName}
|
||||||
|
DefaultGroupName={#MyAppName}
|
||||||
|
OutputBaseFilename={#MyAppName}-{#MyAppVersion}-Windows-Installer
|
||||||
|
Compression=lzma
|
||||||
|
SolidCompression=yes
|
||||||
|
|
||||||
|
[Languages]
|
||||||
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
|
||||||
|
[Files]
|
||||||
|
Source: "..\release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||||
|
Source: "..\LICENSE"; Flags: dontcopy
|
||||||
|
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
||||||
|
|
||||||
|
[Icons]
|
||||||
|
Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}"
|
||||||
|
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
|
||||||
|
|
||||||
|
[Code]
|
||||||
|
procedure InitializeWizard();
|
||||||
|
var
|
||||||
|
GPLText: AnsiString;
|
||||||
|
Page: TOutputMsgMemoWizardPage;
|
||||||
|
begin
|
||||||
|
ExtractTemporaryFile('LICENSE');
|
||||||
|
LoadStringFromFile(ExpandConstant('{tmp}\LICENSE'), GPLText);
|
||||||
|
Page := CreateOutputMsgMemoPage(wpWelcome,
|
||||||
|
'License Information', 'Please review the license terms before installing {#MyAppName}',
|
||||||
|
'Press Page Down to see the rest of the agreement. Once you are aware of your rights, click Next to continue.',
|
||||||
|
String(GPLText)
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// credit where it's due :
|
||||||
|
// following function come from https://github.com/Xaymar/obs-studio_amf-encoder-plugin/blob/master/%23Resources/Installer.in.iss#L45
|
||||||
|
function GetDirName(Value: string): string;
|
||||||
|
var
|
||||||
|
InstallPath: string;
|
||||||
|
begin
|
||||||
|
// initialize default path, which will be returned when the following registry
|
||||||
|
// key queries fail due to missing keys or for some different reason
|
||||||
|
Result := '{autopf}\obs-studio';
|
||||||
|
// query the first registry value; if this succeeds, return the obtained value
|
||||||
|
if RegQueryStringValue(HKLM32, 'SOFTWARE\OBS Studio', '', InstallPath) then
|
||||||
|
Result := InstallPath
|
||||||
|
end;
|
||||||
|
|
3
crowdin.yml
Normal file
3
crowdin.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
files:
|
||||||
|
- source: /data/locale/en-US.ini
|
||||||
|
translation: /data/locale/%locale%.ini
|
@ -1,4 +1,21 @@
|
|||||||
Menu.SettingsItem="Websocket server settings"
|
OBSWebsocketCompat.Settings.DialogTitle="WebSockets Server Settings (4.x Compat)"
|
||||||
Settings.DialogTitle="obs-websocket"
|
OBSWebsocketCompat.Settings.ServerEnable="Enable WebSockets server"
|
||||||
Settings.AuthRequired="Enable authentication"
|
OBSWebsocketCompat.Settings.ServerPort="Server Port"
|
||||||
Settings.Password="Password"
|
OBSWebsocketCompat.Settings.AuthRequired="Enable authentication"
|
||||||
|
OBSWebsocketCompat.Settings.Password="Password"
|
||||||
|
OBSWebsocketCompat.Settings.LockToIPv4="Lock server to only using IPv4"
|
||||||
|
OBSWebsocketCompat.Settings.DebugEnable="Enable debug logging"
|
||||||
|
OBSWebsocketCompat.Settings.AlertsEnable="Enable System Tray Alerts"
|
||||||
|
OBSWebsocketCompat.Settings.AuthDisabledWarning="Running obs-websocket with authentication disabled is not recommended, as it allows attackers to easily collect sensetive data. Are you sure you want to proceed?"
|
||||||
|
OBSWebsocketCompat.NotifyConnect.Title="New WebSocket connection"
|
||||||
|
OBSWebsocketCompat.NotifyConnect.Message="Client %1 connected"
|
||||||
|
OBSWebsocketCompat.NotifyDisconnect.Title="WebSocket client disconnected"
|
||||||
|
OBSWebsocketCompat.NotifyDisconnect.Message="Client %1 disconnected"
|
||||||
|
OBSWebsocketCompat.Server.StartFailed.Title="WebSockets Server failure"
|
||||||
|
OBSWebsocketCompat.Server.StartFailed.Message="The WebSockets compat server failed to start, maybe because:\n - TCP port %1 may currently be in use by the main obs-websocket plugin. Try setting a different TCP port in the obs-websocket Server Settings, or stop any application that could be using this port.\n - Error message: %2"
|
||||||
|
OBSWebsocketCompat.ProfileChanged.Started="WebSockets server enabled in this profile. Server started."
|
||||||
|
OBSWebsocketCompat.ProfileChanged.Stopped="WebSockets server disabled in this profile. Server stopped."
|
||||||
|
OBSWebsocketCompat.ProfileChanged.Restarted="WebSockets server port changed in this profile. Server restarted."
|
||||||
|
OBSWebsocketCompat.InitialPasswordSetup.Title="obs-websocket - Server Password Configuration"
|
||||||
|
OBSWebsocketCompat.InitialPasswordSetup.Text="It looks like you are running obs-websocket for the first time. Do you want to configure a password now for the WebSockets server? Setting a password is highly recommended."
|
||||||
|
OBSWebsocketCompat.InitialPasswordSetup.DismissedText="You can configure a server password later in the WebSockets Server Settings. (Under the Tools menu of OBS Studio)"
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
Menu.SettingsItem="Paramètres du serveur Websocket"
|
|
||||||
Settings.DialogTitle="obs-websocket"
|
|
||||||
Settings.AuthRequired="Activer l'authentification"
|
|
||||||
Settings.Password="Mot de passe"
|
|
1
deps/asio
vendored
Submodule
1
deps/asio
vendored
Submodule
Submodule deps/asio added at b73dc1d2c0
1
deps/mbedtls
vendored
1
deps/mbedtls
vendored
Submodule deps/mbedtls deleted from 1a6a15c795
1
deps/websocketpp
vendored
Submodule
1
deps/websocketpp
vendored
Submodule
Submodule deps/websocketpp added at 56123c8759
11
docs/.editorconfig
Normal file
11
docs/.editorconfig
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md, *.mustache]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
insert_final_newline = false
|
4
docs/.gitignore
vendored
Normal file
4
docs/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
node_modules
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
1
docs/.npmrc
Normal file
1
docs/.npmrc
Normal file
@ -0,0 +1 @@
|
|||||||
|
package-lock=false
|
21
docs/README.md
Normal file
21
docs/README.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
## Installation
|
||||||
|
|
||||||
|
Install node and update npm if necessary.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd obs-websocket/docs
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Just extract the comments.
|
||||||
|
npm run comments
|
||||||
|
|
||||||
|
# Just render the markdown.
|
||||||
|
npm run docs
|
||||||
|
|
||||||
|
# Do both comments and markdown.
|
||||||
|
npm run build
|
||||||
|
```
|
104
docs/comments.js
Normal file
104
docs/comments.js
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const glob = require('glob');
|
||||||
|
const parseComments = require('parse-comments');
|
||||||
|
const config = require('./config.json');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read each file and call `parse-comments` on it.
|
||||||
|
*
|
||||||
|
* @param {String|Array} `files` List of file paths to read from.
|
||||||
|
* @return {Object|Array} Array of `parse-comments` objects.
|
||||||
|
*/
|
||||||
|
const parseFiles = files => {
|
||||||
|
let response = [];
|
||||||
|
files.forEach(file => {
|
||||||
|
const f = fs.readFileSync(file, 'utf8').toString();
|
||||||
|
response = response.concat(parseComments(f));
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters/sorts the results from `parse-comments`.
|
||||||
|
* @param {Object|Array} `comments` Array of `parse-comments` objects.
|
||||||
|
* @return {Object} Filtered comments sorted by `@api` and `@category`.
|
||||||
|
*/
|
||||||
|
const processComments = comments => {
|
||||||
|
let sorted = {};
|
||||||
|
let errors = [];
|
||||||
|
|
||||||
|
comments.forEach(comment => {
|
||||||
|
if (comment.typedef) {
|
||||||
|
comment.comment = undefined;
|
||||||
|
comment.context = undefined;
|
||||||
|
sorted['typedefs'] = sorted['typedefs'] || [];
|
||||||
|
sorted['typedefs'].push(comment);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof comment.api === 'undefined') return;
|
||||||
|
let validationFailures = validateComment(comment);
|
||||||
|
|
||||||
|
if (validationFailures) {
|
||||||
|
errors.push(validationFailures);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the object based on its api (ie. requests, events) and category (ie. general, scenes, etc).
|
||||||
|
comment.category = comment.category || 'miscellaneous';
|
||||||
|
|
||||||
|
// Remove some unnecessary properties to avoid result differences in travis.
|
||||||
|
comment.comment = undefined;
|
||||||
|
comment.context = undefined;
|
||||||
|
|
||||||
|
// Create an entry in sorted for the api/category if one does not exist.
|
||||||
|
sorted[comment.api] = sorted[comment.api] || {};
|
||||||
|
sorted[comment.api][comment.category] = sorted[comment.api][comment.category] || [];
|
||||||
|
|
||||||
|
// Store the comment in the appropriate api/category.
|
||||||
|
sorted[comment.api][comment.category].push(comment);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (errors.length) {
|
||||||
|
throw JSON.stringify(errors, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sorted;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Rudimentary validation of documentation content, returns an error object or undefined.
|
||||||
|
const validateComment = comment => {
|
||||||
|
let errors = [];
|
||||||
|
[].concat(comment.params).concat(comment.returns).filter(Boolean).forEach(param => {
|
||||||
|
if (typeof param.name !== 'string' || param.name === '') {
|
||||||
|
errors.push({
|
||||||
|
description: `Invalid param or return value name`,
|
||||||
|
param: param
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof param.type !== 'string' || param.type === '') {
|
||||||
|
errors.push({
|
||||||
|
description: `Invalid param or return value type`,
|
||||||
|
param: param
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (errors.length) {
|
||||||
|
return {
|
||||||
|
errors: errors,
|
||||||
|
fullContext: Object.assign({}, comment)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const files = glob.sync(config.srcGlob);
|
||||||
|
const comments = processComments(parseFiles(files));
|
||||||
|
|
||||||
|
if (!fs.existsSync(config.outDirectory)){
|
||||||
|
fs.mkdirSync(config.outDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(path.join(config.outDirectory, 'comments.json'), JSON.stringify(comments, null, 2));
|
5
docs/config.json
Normal file
5
docs/config.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"srcGlob": "./../src/**/*.@(cpp|h)",
|
||||||
|
"srcTemplate": "./protocol.hbs",
|
||||||
|
"outDirectory": "./generated"
|
||||||
|
}
|
37
docs/docs.js
Normal file
37
docs/docs.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const toc = require('markdown-toc');
|
||||||
|
const handlebars = require('handlebars');
|
||||||
|
const config = require('./config.json');
|
||||||
|
|
||||||
|
const helpers = require('handlebars-helpers')({
|
||||||
|
handlebars: handlebars
|
||||||
|
});
|
||||||
|
|
||||||
|
// Allows pipe characters to be used within markdown tables.
|
||||||
|
handlebars.registerHelper('depipe', (text) => {
|
||||||
|
return typeof text === 'string' ? text.replace('|', '\\|') : text;
|
||||||
|
});
|
||||||
|
|
||||||
|
const insertHeader = (text) => {
|
||||||
|
return '<!-- This file was generated based on handlebars templates. Do not edit directly! -->\n\n' + text;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes `protocol.md` using `protocol.mustache`.
|
||||||
|
*
|
||||||
|
* @param {Object} `data` Data to assign to the mustache template.
|
||||||
|
*/
|
||||||
|
const generateProtocol = (templatePath, data) => {
|
||||||
|
const template = fs.readFileSync(templatePath).toString();
|
||||||
|
const generated = handlebars.compile(template)(data);
|
||||||
|
return insertHeader(toc.insert(generated));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!fs.existsSync(config.outDirectory)){
|
||||||
|
fs.mkdirSync(config.outDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
const comments = fs.readFileSync(path.join(config.outDirectory, 'comments.json'), 'utf8');
|
||||||
|
const markdown = generateProtocol(config.srcTemplate, JSON.parse(comments));
|
||||||
|
fs.writeFileSync(path.join(config.outDirectory, 'protocol.md'), markdown);
|
11582
docs/generated/comments.json
Normal file
11582
docs/generated/comments.json
Normal file
File diff suppressed because it is too large
Load Diff
4640
docs/generated/protocol.md
Normal file
4640
docs/generated/protocol.md
Normal file
File diff suppressed because it is too large
Load Diff
21
docs/package.json
Normal file
21
docs/package.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "obs-websocket-docs",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "docs.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"docs": "node ./docs.js",
|
||||||
|
"comments": "node ./comments.js",
|
||||||
|
"build": "npm run comments && npm run docs"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"glob": "^7.1.2",
|
||||||
|
"handlebars": "^4.0.10",
|
||||||
|
"handlebars-helpers": "^0.9.6",
|
||||||
|
"markdown-toc": "^1.1.0",
|
||||||
|
"parse-comments": "^0.4.3"
|
||||||
|
}
|
||||||
|
}
|
11
docs/partials/eventsHeader.md
Normal file
11
docs/partials/eventsHeader.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Events
|
||||||
|
Events are broadcast by the server to each connected client when a recognized action occurs within OBS.
|
||||||
|
|
||||||
|
An event message will contain at least the following base fields:
|
||||||
|
- `update-type` _String_: the type of event.
|
||||||
|
- `stream-timecode` _String (optional)_: time elapsed between now and stream start (only present if OBS Studio is streaming).
|
||||||
|
- `rec-timecode` _String (optional)_: time elapsed between now and recording start (only present if OBS Studio is recording).
|
||||||
|
|
||||||
|
Timecodes are sent using the format: `HH:MM:SS.mmm`
|
||||||
|
|
||||||
|
Additional fields may be present in the event message depending on the event type.
|
38
docs/partials/introduction.md
Normal file
38
docs/partials/introduction.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# obs-websocket 4.9.1 protocol reference
|
||||||
|
|
||||||
|
# General Introduction
|
||||||
|
Messages are exchanged between the client and the server as JSON objects.
|
||||||
|
This protocol is based on the original OBS Remote protocol created by Bill Hamilton, with new commands specific to OBS Studio. As of v5.0.0, backwards compatability with the protocol will not be kept.
|
||||||
|
|
||||||
|
# Authentication
|
||||||
|
**Starting with obs-websocket 4.9, authentication is enabled by default and users are encouraged to configure a password on first run.**
|
||||||
|
|
||||||
|
`obs-websocket` uses SHA256 to transmit credentials.
|
||||||
|
|
||||||
|
A request for [`GetAuthRequired`](#getauthrequired) returns two elements:
|
||||||
|
- A `challenge`: a random string that will be used to generate the auth response.
|
||||||
|
- A `salt`: applied to the password when generating the auth response.
|
||||||
|
|
||||||
|
To generate the answer to the auth challenge, follow this procedure:
|
||||||
|
- Concatenate the user declared password with the `salt` sent by the server (in this order: `password + server salt`).
|
||||||
|
- Generate a binary SHA256 hash of the result and encode the resulting SHA256 binary hash to base64, known as a `base64 secret`.
|
||||||
|
- Concatenate the base64 secret with the `challenge` sent by the server (in this order: `base64 secret + server challenge`).
|
||||||
|
- Generate a binary SHA256 hash of the result and encode it to base64.
|
||||||
|
- Voilà, this last base64 string is the `auth response`. You may now use it to authenticate to the server with the [`Authenticate`](#authenticate) request.
|
||||||
|
|
||||||
|
Pseudo Code Example:
|
||||||
|
```
|
||||||
|
password = "supersecretpassword"
|
||||||
|
challenge = "ztTBnnuqrqaKDzRM3xcVdbYm"
|
||||||
|
salt = "PZVbYpvAnZut2SS6JNJytDm9"
|
||||||
|
|
||||||
|
secret_string = password + salt
|
||||||
|
secret_hash = binary_sha256(secret_string)
|
||||||
|
secret = base64_encode(secret_hash)
|
||||||
|
|
||||||
|
auth_response_string = secret + challenge
|
||||||
|
auth_response_hash = binary_sha256(auth_response_string)
|
||||||
|
auth_response = base64_encode(auth_response_hash)
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also refer to any of the [client libraries](https://github.com/Palakis/obs-websocket#for-developers) listed on the README for examples of how to authenticate.
|
11
docs/partials/requestsHeader.md
Normal file
11
docs/partials/requestsHeader.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Requests
|
||||||
|
Requests are sent by the client and require at least the following two fields:
|
||||||
|
- `request-type` _String_: String name of the request type.
|
||||||
|
- `message-id` _String_: Client defined identifier for the message, will be echoed in the response.
|
||||||
|
|
||||||
|
Once a request is sent, the server will return a JSON response with at least the following fields:
|
||||||
|
- `message-id` _String_: The client defined identifier specified in the request.
|
||||||
|
- `status` _String_: Response status, will be one of the following: `ok`, `error`
|
||||||
|
- `error` _String (Optional)_: An error message accompanying an `error` status.
|
||||||
|
|
||||||
|
Additional information may be required/returned depending on the request type. See below for more information.
|
2
docs/partials/typedefsHeader.md
Normal file
2
docs/partials/typedefsHeader.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Typedefs
|
||||||
|
These are complex types, such as `Source` and `Scene`, which are used as arguments or return values in multiple requests and/or events.
|
112
docs/protocol.hbs
Normal file
112
docs/protocol.hbs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
{{#read "partials/introduction.md"}}{{/read}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Table of Contents
|
||||||
|
<!-- toc -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{{#read "partials/typedefsHeader.md"}}{{/read}}
|
||||||
|
|
||||||
|
{{#each typedefs}}
|
||||||
|
## {{typedefs.0.name}}
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | :---: | ------------|
|
||||||
|
{{#each properties}}
|
||||||
|
| `{{name}}` | _{{depipe type}}_ | {{{depipe description}}} |
|
||||||
|
{{/each}}
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{{#read "partials/eventsHeader.md"}}{{/read}}
|
||||||
|
|
||||||
|
{{#each events}}
|
||||||
|
## {{capitalizeAll @key}}
|
||||||
|
|
||||||
|
{{#each this}}
|
||||||
|
### {{name}}
|
||||||
|
|
||||||
|
{{#if deprecated}}
|
||||||
|
- **⚠️ Deprecated. {{deprecated}} ⚠️**
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#eq since "unreleased"}}
|
||||||
|
- Unreleased
|
||||||
|
{{else}}
|
||||||
|
- Added in v{{since}}
|
||||||
|
{{/eq}}
|
||||||
|
|
||||||
|
{{{description}}}
|
||||||
|
|
||||||
|
**Response Items:**
|
||||||
|
|
||||||
|
{{#if returns.length}}
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | :---: | ------------|
|
||||||
|
{{#each returns}}
|
||||||
|
| `{{name}}` | _{{depipe type}}_ | {{{depipe description}}} |
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
_No additional response items._
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
{{/each}}
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{{#read "partials/requestsHeader.md"}}{{/read}}
|
||||||
|
|
||||||
|
{{#each requests}}
|
||||||
|
## {{capitalizeAll @key}}
|
||||||
|
|
||||||
|
{{#each this}}
|
||||||
|
### {{name}}
|
||||||
|
|
||||||
|
{{#if deprecated}}
|
||||||
|
- **⚠️ Deprecated. {{deprecated}} ⚠️**
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#eq since "unreleased"}}
|
||||||
|
- Unreleased
|
||||||
|
{{else}}
|
||||||
|
- Added in v{{since}}
|
||||||
|
{{/eq}}
|
||||||
|
|
||||||
|
{{{description}}}
|
||||||
|
|
||||||
|
**Request Fields:**
|
||||||
|
|
||||||
|
{{#if params.length}}
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | :---: | ------------|
|
||||||
|
{{#each params}}
|
||||||
|
| `{{name}}` | _{{depipe type}}_ | {{{depipe description}}} |
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
_No specified parameters._
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
**Response Items:**
|
||||||
|
|
||||||
|
{{#if returns.length}}
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | :---: | ------------|
|
||||||
|
{{#each returns}}
|
||||||
|
| `{{name}}` | _{{depipe type}}_ | {{{depipe description}}} |
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
_No additional response items._
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
{{/each}}
|
||||||
|
{{/each}}
|
107
external/FindLibObs.cmake
vendored
107
external/FindLibObs.cmake
vendored
@ -1,107 +0,0 @@
|
|||||||
# This module can be copied and used by external plugins for OBS
|
|
||||||
#
|
|
||||||
# Once done these will be defined:
|
|
||||||
#
|
|
||||||
# LIBOBS_FOUND
|
|
||||||
# LIBOBS_INCLUDE_DIRS
|
|
||||||
# LIBOBS_LIBRARIES
|
|
||||||
|
|
||||||
find_package(PkgConfig QUIET)
|
|
||||||
if (PKG_CONFIG_FOUND)
|
|
||||||
pkg_check_modules(_OBS QUIET obs libobs)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
|
||||||
set(_lib_suffix 64)
|
|
||||||
else()
|
|
||||||
set(_lib_suffix 32)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(DEFINED CMAKE_BUILD_TYPE)
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
||||||
set(_build_type_base "debug")
|
|
||||||
else()
|
|
||||||
set(_build_type_base "release")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_path(LIBOBS_INCLUDE_DIR
|
|
||||||
NAMES obs.h
|
|
||||||
HINTS
|
|
||||||
ENV obsPath${_lib_suffix}
|
|
||||||
ENV obsPath
|
|
||||||
${obsPath}
|
|
||||||
PATHS
|
|
||||||
/usr/include /usr/local/include /opt/local/include /sw/include
|
|
||||||
PATH_SUFFIXES
|
|
||||||
libobs
|
|
||||||
)
|
|
||||||
|
|
||||||
function(find_obs_lib base_name repo_build_path lib_name)
|
|
||||||
string(TOUPPER "${base_name}" base_name_u)
|
|
||||||
|
|
||||||
if(DEFINED _build_type_base)
|
|
||||||
set(_build_type_${repo_build_path} "${_build_type_base}/${repo_build_path}")
|
|
||||||
set(_build_type_${repo_build_path}${_lib_suffix} "${_build_type_base}${_lib_suffix}/${repo_build_path}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_library(${base_name_u}_LIB
|
|
||||||
NAMES ${_${base_name_u}_LIBRARIES} ${lib_name} lib${lib_name}
|
|
||||||
HINTS
|
|
||||||
ENV obsPath${_lib_suffix}
|
|
||||||
ENV obsPath
|
|
||||||
${obsPath}
|
|
||||||
${_${base_name_u}_LIBRARY_DIRS}
|
|
||||||
PATHS
|
|
||||||
/usr/lib /usr/local/lib /opt/local/lib /sw/lib
|
|
||||||
PATH_SUFFIXES
|
|
||||||
lib${_lib_suffix} lib
|
|
||||||
libs${_lib_suffix} libs
|
|
||||||
bin${_lib_suffix} bin
|
|
||||||
../lib${_lib_suffix} ../lib
|
|
||||||
../libs${_lib_suffix} ../libs
|
|
||||||
../bin${_lib_suffix} ../bin
|
|
||||||
# base repo non-msvc-specific search paths
|
|
||||||
${_build_type_${repo_build_path}}
|
|
||||||
${_build_type_${repo_build_path}${_lib_suffix}}
|
|
||||||
build/${repo_build_path}
|
|
||||||
build${_lib_suffix}/${repo_build_path}
|
|
||||||
# base repo msvc-specific search paths on windows
|
|
||||||
build${_lib_suffix}/${repo_build_path}/Debug
|
|
||||||
build${_lib_suffix}/${repo_build_path}/RelWithDebInfo
|
|
||||||
build/${repo_build_path}/Debug
|
|
||||||
build/${repo_build_path}/RelWithDebInfo
|
|
||||||
)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
find_obs_lib(LIBOBS libobs obs)
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
find_obs_lib(W32_PTHREADS deps/w32-pthreads w32-pthreads)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(Libobs DEFAULT_MSG LIBOBS_LIB LIBOBS_INCLUDE_DIR)
|
|
||||||
mark_as_advanced(LIBOBS_INCLUDE_DIR LIBOBS_LIB)
|
|
||||||
|
|
||||||
if(LIBOBS_FOUND)
|
|
||||||
if(MSVC)
|
|
||||||
if (NOT DEFINED W32_PTHREADS_LIB)
|
|
||||||
message(FATAL_ERROR "Could not find the w32-pthreads library" )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(W32_PTHREADS_INCLUDE_DIR ${LIBOBS_INCLUDE_DIR}/../deps/w32-pthreads)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(LIBOBS_INCLUDE_DIRS ${LIBOBS_INCLUDE_DIR} ${W32_PTHREADS_INCLUDE_DIR})
|
|
||||||
set(LIBOBS_LIBRARIES ${LIBOBS_LIB} ${W32_PTHREADS_LIB})
|
|
||||||
include(${LIBOBS_INCLUDE_DIR}/../cmake/external/ObsPluginHelpers.cmake)
|
|
||||||
|
|
||||||
# allows external plugins to easily use/share common dependencies that are often included with libobs (such as FFmpeg)
|
|
||||||
if(NOT DEFINED INCLUDED_LIBOBS_CMAKE_MODULES)
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${LIBOBS_INCLUDE_DIR}/../cmake/Modules/")
|
|
||||||
set(INCLUDED_LIBOBS_CMAKE_MODULES true)
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
message(FATAL_ERROR "Could not find the libobs library" )
|
|
||||||
endif()
|
|
@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
obs-websocket
|
|
||||||
Copyright (C) 2016 Stéphane Lepin <stephane.lepin@gmail.com>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program. If not, see <https://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <obs-frontend-api.h>
|
|
||||||
#include "settings-dialog.h"
|
|
||||||
#include "ui_settings-dialog.h"
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
#define CHANGE_ME "changeme"
|
|
||||||
|
|
||||||
SettingsDialog::SettingsDialog(QWidget *parent) :
|
|
||||||
QDialog(parent),
|
|
||||||
ui(new Ui::SettingsDialog)
|
|
||||||
{
|
|
||||||
ui->setupUi(this);
|
|
||||||
|
|
||||||
connect(ui->authRequired, &QCheckBox::stateChanged, this, &SettingsDialog::AuthCheckboxChanged);
|
|
||||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &SettingsDialog::FormAccepted);
|
|
||||||
|
|
||||||
AuthCheckboxChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsDialog::showEvent(QShowEvent *event) {
|
|
||||||
ui->authRequired->setChecked(Config::Current()->AuthRequired);
|
|
||||||
ui->password->setText(CHANGE_ME);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsDialog::ToggleShowHide() {
|
|
||||||
if (!isVisible()) {
|
|
||||||
setVisible(true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setVisible(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsDialog::AuthCheckboxChanged() {
|
|
||||||
if (ui->authRequired->isChecked()) {
|
|
||||||
ui->password->setEnabled(true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ui->password->setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsDialog::FormAccepted() {
|
|
||||||
if (ui->authRequired->isChecked()) {
|
|
||||||
if (ui->password->text() != CHANGE_ME) {
|
|
||||||
QByteArray pwd = ui->password->text().toLocal8Bit();
|
|
||||||
const char *new_password = pwd;
|
|
||||||
|
|
||||||
blog(LOG_INFO, "new password : %s", new_password);
|
|
||||||
Config::Current()->SetPassword(new_password);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(Config::Current()->Secret, "") != 0) {
|
|
||||||
Config::Current()->AuthRequired = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Config::Current()->AuthRequired = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Config::Current()->AuthRequired = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_frontend_save();
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsDialog::~SettingsDialog()
|
|
||||||
{
|
|
||||||
delete ui;
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user