Compare commits
969 Commits
Author | SHA1 | Date |
---|---|---|
|
e6ef1ff395 | |
|
8e9a57bcd3 | |
|
4dc988c5bb | |
|
bc081cfe63 | |
|
6c8d2d712d | |
|
b4a974a33e | |
|
b21b899303 | |
|
5597aea828 | |
|
5d31bf0020 | |
|
91ad944c46 | |
|
cb63194fc6 | |
|
7f8a9d4289 | |
|
8e8fac92d1 | |
|
7e24c70454 | |
|
a9f20ebf36 | |
|
4b8c8ee842 | |
|
5bad15a79a | |
|
9b7d1a3e5c | |
|
5f7fa6287f | |
|
2af8b4b209 | |
|
66096fa2ea | |
|
18875a01c6 | |
|
7d2c2b9d09 | |
|
67a290a02a | |
|
63f4278b2b | |
|
6778f871db | |
|
edc72a5486 | |
|
2779258111 | |
|
da735779b4 | |
|
b7e2e912f4 | |
|
d34172d8e9 | |
|
f30ce78f9d | |
|
ed767aedb5 | |
|
ab35895cb3 | |
|
1e2b65644d | |
|
3f58bbc617 | |
|
c1da7b53a2 | |
|
4181c22995 | |
|
d31ac53bd1 | |
|
9b954852aa | |
|
3758916fb5 | |
|
25c1395655 | |
|
440edd7b18 | |
|
a2f045841f | |
|
c890107e1e | |
|
a5df1650b9 | |
|
173ce499bc | |
|
33412b0588 | |
|
3c5e31a961 | |
|
39676f9a06 | |
|
0f893d94c4 | |
|
b08f5094d5 | |
|
70e046eeb7 | |
|
58d0742187 | |
|
f84e8b741a | |
|
fcf24b5539 | |
|
128a4d2ded | |
|
b14d24e650 | |
|
7995665c6b | |
|
a22906d3c2 | |
|
042533dc85 | |
|
5fbefeecbf | |
|
a9772ff081 | |
|
cdf983c7c6 | |
|
03f886580f | |
|
a06e2869b9 | |
|
6bafb263de | |
|
493ff5fbf6 | |
|
c29e0880ac | |
|
986c7a915b | |
|
68b1b8b819 | |
|
382ba56fa7 | |
|
24d6685047 | |
|
565d2ecceb | |
|
c4456e458f | |
|
f707dedc91 | |
|
702fc4680d | |
|
99b63150ac | |
|
6e7c226c57 | |
|
c8e5f7b742 | |
|
0cf147d185 | |
|
cf1514f53e | |
|
af3843a8ef | |
|
91ce2dd450 | |
|
71c9efae42 | |
|
08ce0d792b | |
|
754ef17b74 | |
|
5d4fec8c81 | |
|
1e0338a77f | |
|
e6b9628746 | |
|
6f68081dc5 | |
|
66b18dd351 | |
|
b5f5b6461a | |
|
6dd29d9596 | |
|
29ba125534 | |
|
144af1414c | |
|
06906eca42 | |
|
0d47748d6a | |
|
b1c8192625 | |
|
d2c7781d79 | |
|
37d4f50ef4 | |
|
082ac85c5c | |
|
cfca56ba48 | |
|
c7cb4ddbc5 | |
|
7f98d6028b | |
|
401822a7bb | |
|
173ba06590 | |
|
2677118bad | |
|
8e90456d87 | |
|
0b880a5e79 | |
|
082dbc0826 | |
|
5eccbbf6df | |
|
513deb7a0a | |
|
2b24dc647c | |
|
f8e5968f30 | |
|
18b8c84fff | |
|
1d6ccb7838 | |
|
a7a63a3be7 | |
|
153ef9eceb | |
|
eec7765e73 | |
|
03f2b55762 | |
|
6714374639 | |
|
b6b1f5d5ba | |
|
d7a10f9737 | |
|
d778adc7d0 | |
|
dcbb57f732 | |
|
24452794a9 | |
|
24fe1e8773 | |
|
b30c637c10 | |
|
f16795b11c | |
|
141d27599f | |
|
86c88c4ac2 | |
|
fbab0c043a | |
|
1a01a4f05e | |
|
b0305ae6da | |
|
dd4834de04 | |
|
2d90c127a3 | |
|
51d440fccc | |
|
2e3ed56bb3 | |
|
4be57f3128 | |
|
de6f0d0495 | |
|
98e1e73163 | |
|
1ae524ff31 | |
|
010927c5ca | |
|
3346bf01af | |
|
788cac7d50 | |
|
4c0fa2ba41 | |
|
83209f466f | |
|
10c452c1b3 | |
|
a8a33a823a | |
|
e7e7f86ab3 | |
|
386285d48c | |
|
c4119ab7cc | |
|
176643f148 | |
|
8b235bb6b0 | |
|
8a170f65ca | |
|
2f56dd4b8a | |
|
699c2dbec8 | |
|
dac720863d | |
|
3b03eb70fb | |
|
a173cf0d7c | |
|
55b39e7db3 | |
|
505a2a71e7 | |
|
fb51716e3a | |
|
bdd74fa90a | |
|
8631250b9e | |
|
c9f35ffe90 | |
|
18d6e2c7cd | |
|
f47ea2d382 | |
|
0cc167b3a6 | |
|
5133295f38 | |
|
621948fbac | |
|
4539c6d897 | |
|
a7db072dc6 | |
|
58ce079330 | |
|
dd03583a27 | |
|
3feaea74bf | |
|
1d6cbe5c53 | |
|
318f931dbf | |
|
5400518ea6 | |
|
f73a1e3931 | |
|
60d7ab4b5e | |
|
95cde2907a | |
|
35b67f1815 | |
|
f958789b20 | |
|
4beef04a3f | |
|
6d379d284b | |
|
2c21110b97 | |
|
777db577d7 | |
|
bf320216cf | |
|
b48c498574 | |
|
0b71da8e7b | |
|
c0d6cbccec | |
|
95ede98623 | |
|
3881dd4891 | |
|
71e4bea384 | |
|
83aa3099c4 | |
|
672db32917 | |
|
80a9c23f4d | |
|
49ad3c28a8 | |
|
a29c85628c | |
|
3ec93ab3b1 | |
|
10c29d3af1 | |
|
41840b90c8 | |
|
c89e865d3d | |
|
c6ec54bd06 | |
|
af3b1b8cbb | |
|
86273a9f09 | |
|
ba0241a811 | |
|
1bd73876b4 | |
|
cc806cbe52 | |
|
8f7a40075a | |
|
64faaa9427 | |
|
d44c67ce80 | |
|
144b408092 | |
|
d2390dca30 | |
|
503a8ec92f | |
|
ca22a3ba4b | |
|
ef54e61494 | |
|
b1745c786b | |
|
83efbc18c7 | |
|
f47396e48c | |
|
03c27a9226 | |
|
08655898d4 | |
|
5d347d23e4 | |
|
a25d93ec55 | |
|
bbf0cbd1c6 | |
|
4aceeac1c2 | |
|
1f5bb85304 | |
|
087fd3f763 | |
|
daece3b45a | |
|
9705505285 | |
|
9016062f70 | |
|
a6de66eb66 | |
|
6ada6b08ed | |
|
710e178ba2 | |
|
9e7990851e | |
|
ae34558f18 | |
|
c1a51f1ce8 | |
|
13702a3d5b | |
|
6b66cfe03f | |
|
cbc876c57c | |
|
7813a8c904 | |
|
5f941e91b5 | |
|
d262ed418d | |
|
2e9db4d667 | |
|
bd9317dd8f | |
|
461add1cda | |
|
1528dec668 | |
|
fff9d5d410 | |
|
231c354cb1 | |
|
4e0149e752 | |
|
5c6b9191e5 | |
|
77a0f7d8a0 | |
|
9faae6fc36 | |
|
3689eb7528 | |
|
210dc85558 | |
|
174b900cd8 | |
|
fbe954280f | |
|
142c990a0e | |
|
790ea3d551 | |
|
c6b8592490 | |
|
f67e011d5e | |
|
a4bc54482d | |
|
be50eb6fcf | |
|
a7d784583a | |
|
7af1f739e4 | |
|
3e247703a8 | |
|
c7e338ebff | |
|
cc2af435d5 | |
|
87695b173d | |
|
722ff9c05e | |
|
51114df576 | |
|
9126bc82c0 | |
|
e09fe7d42f | |
|
234e69c7a2 | |
|
d7017af245 | |
|
f49c70ead6 | |
|
9a89dbe6a5 | |
|
844bb286a5 | |
|
4eceecf139 | |
|
95e2e997e5 | |
|
346c303edb | |
|
908fe52ad8 | |
|
3fd1e47b7b | |
|
d41f082839 | |
|
2047ce4f76 | |
|
3ef56cab21 | |
|
6b77b98aad | |
|
211101cd6b | |
|
e27cae353f | |
|
b12a08e47a | |
|
9b298ac676 | |
|
52acb97e08 | |
|
78450e9e6a | |
|
dc746fe6f4 | |
|
0e3bc563a7 | |
|
d0ef5d410d | |
|
d9aa7dc698 | |
|
70ab8cb527 | |
|
512f6c86ad | |
|
d23eb290d9 | |
|
648bca5b2e | |
|
5db5d477e4 | |
|
7741134917 | |
|
3c19cd35cf | |
|
85832d18f6 | |
|
5f0da91659 | |
|
e1bf69e622 | |
|
d9290f7262 | |
|
81b6846261 | |
|
a57519adce | |
|
02639466ee | |
|
6e2795d380 | |
|
8e35596088 | |
|
0162d012c5 | |
|
47fb673b78 | |
|
f296488bc2 | |
|
f5392aea9f | |
|
24b1301f9f | |
|
1290a8f324 | |
|
e64277e438 | |
|
c9bcb74a9f | |
|
42db1f81b8 | |
|
7222952eba | |
|
744f10c948 | |
|
b50704a6a8 | |
|
c152806511 | |
|
4d9454daf2 | |
|
e754c65602 | |
|
b672921c84 | |
|
6116ada2fd | |
|
d7baa4d17b | |
|
ebc5504998 | |
|
c5e66a6f40 | |
|
cff558ef9a | |
|
325837d93e | |
|
135540b261 | |
|
49464cd25a | |
|
d0fe54b429 | |
|
2dce6f4b08 | |
|
99794d04c2 | |
|
cc06655cd6 | |
|
ab6f517d27 | |
|
682167db48 | |
|
f127dc1128 | |
|
0b816ae8e1 | |
|
c600fea4e1 | |
|
92067bdbef | |
|
c181e003a3 | |
|
597137670d | |
|
3036aebbc4 | |
|
cbe6477af2 | |
|
c2546d2bc5 | |
|
46be1bfd3b | |
|
1029885047 | |
|
164bde8cce | |
|
41504caac9 | |
|
9b34b4e026 | |
|
95612c1d18 | |
|
0829ec9081 | |
|
ef0d246901 | |
|
622a8a7c42 | |
|
925659ba4b | |
|
20c9287ac2 | |
|
8aaa2b8940 | |
|
30bd35e21d | |
|
0c2e39f0b2 | |
|
cbd7001228 | |
|
dec96ec9be | |
|
3942cd05be | |
|
ee1e9c9feb | |
|
fcb77232ec | |
|
1fcbec7466 | |
|
98f2c7a24a | |
|
787e6ed06e | |
|
bb5b7c7897 | |
|
42b3aa767d | |
|
b20a6084e6 | |
|
d9a8576701 | |
|
69273d2a1c | |
|
755ea757f7 | |
|
81fc54af8d | |
|
4281ca4390 | |
|
3419172535 | |
|
206c266b08 | |
|
5026cf869f | |
|
d5ecd9e057 | |
|
72b5077356 | |
|
6601c030f7 | |
|
3ec1373f08 | |
|
b29478cb58 | |
|
fe61e63e76 | |
|
ee0ab663d7 | |
|
1964d6002d | |
|
f55b72044c | |
|
3f759f5678 | |
|
6582154ec6 | |
|
9d0545aa4f | |
|
ea055d6e56 | |
|
bc48765b35 | |
|
70c2c695f0 | |
|
8ec5816364 | |
|
c33c6e24f6 | |
|
b0ca15bd8d | |
|
76799bd66d | |
|
18dbb72a54 | |
|
c0ec81c0f9 | |
|
c3661d6ff1 | |
|
c0f056cd8d | |
|
2924efe39f | |
|
e275539fb0 | |
|
4c13c54815 | |
|
62a66f5f6d | |
|
3a435933e3 | |
|
78f7ac0e68 | |
|
28dc19fc32 | |
|
585c47d6c7 | |
|
04a0330327 | |
|
dae4e65aee | |
|
129647b863 | |
|
2f9201716a | |
|
f9d716552b | |
|
818c8453ee | |
|
f7a3c52260 | |
|
9d3bf24627 | |
|
c77201ef4e | |
|
f585aa2a5a | |
|
96e0ce6050 | |
|
17d4ff459f | |
|
c15c376a2f | |
|
22bed4632b | |
|
8b5faaa1a4 | |
|
81d94fd727 | |
|
bbfe6fc657 | |
|
467a5c06d6 | |
|
9dce9fb1f2 | |
|
e1c8ba1320 | |
|
4ef318c55e | |
|
7f7513809a | |
|
b3bb07454f | |
|
faad084b2b | |
|
3e528c23a5 | |
|
6fed941441 | |
|
6fee5a803c | |
|
2861bc52fd | |
|
8c14a06b96 | |
|
3e0ac3f0d0 | |
|
394fbe2323 | |
|
11267796ba | |
|
aac5e5d488 | |
|
8a6bc0b4f5 | |
|
a2af605d37 | |
|
32f70be614 | |
|
31c701734a | |
|
fb7b1e2fb6 | |
|
5061a511ab | |
|
c0121bcfe7 | |
|
66639e951b | |
|
53d147b9bc | |
|
ad1ac51fc8 | |
|
88a6e9f563 | |
|
7dc4d153be | |
|
dcc91501ee | |
|
6473f388d8 | |
|
a21fff82f1 | |
|
2c8eabeffd | |
|
85bfa57127 | |
|
112e6b543c | |
|
232f39b861 | |
|
338a60f947 | |
|
9ab1436d49 | |
|
8d3c035e7b | |
|
10b823bca8 | |
|
7f9020e698 | |
|
6a563e131b | |
|
1fb5c984ac | |
|
b90a68cb39 | |
|
7ebfe16897 | |
|
e84f1ce8ff | |
|
eb7e62aac7 | |
|
dab5c67c04 | |
|
69ca62f884 | |
|
53941835cb | |
|
7d4e53fe24 | |
|
6f19842da0 | |
|
3692195887 | |
|
e672c2dc93 | |
|
65292524b1 | |
|
5e481e77b0 | |
|
7c9543239e | |
|
8672b6584a | |
|
c5d7f9c91f | |
|
9502d255c7 | |
|
08c3c23da0 | |
|
6eeeae85c8 | |
|
7c61af7043 | |
|
d501623290 | |
|
0ccb29dfb0 | |
|
f02782d4da | |
|
c2e83ab27b | |
|
32356b0037 | |
|
dd1bec8394 | |
|
4f2252d113 | |
|
0145bebb4b | |
|
5e6fbbb43c | |
|
7e516a59b6 | |
|
948b20fead | |
|
c61c128044 | |
|
296ef93ecb | |
|
74621ef1fb | |
|
0811222d27 | |
|
0c364576c9 | |
|
7ff49f0aa6 | |
|
a9b678f748 | |
|
f2fd77a858 | |
|
8c97258866 | |
|
5c691a8e12 | |
|
e5e4c7ded7 | |
|
a748f689bd | |
|
5309f85638 | |
|
efc6d0ef03 | |
|
a379e4b086 | |
|
4a1bf417a4 | |
|
b702929e1f | |
|
d042381293 | |
|
9805127387 | |
|
270862bd5f | |
|
53e012018f | |
|
420a3fbd50 | |
|
5258fcbf30 | |
|
4db3ce8b88 | |
|
e3d36a1f27 | |
|
67d0e750c2 | |
|
f4eb066725 | |
|
fb63bade2f | |
|
ed0175b733 | |
|
8163f7d454 | |
|
5ec50713ba | |
|
37719b9974 | |
|
3fd2b04e75 | |
|
c15cd512ae | |
|
cc41b75130 | |
|
f929ea2cc2 | |
|
d4987ed3a3 | |
|
da00c62db3 | |
|
55c460fbb4 | |
|
01cac728f5 | |
|
8d5663d3a2 | |
|
1c940d6df7 | |
|
891c34ad88 | |
|
aec5b79f90 | |
|
e25a8bbc7c | |
|
d70de98256 | |
|
aec3e29476 | |
|
32fe873707 | |
|
549cd3cc04 | |
|
8dc955a5e7 | |
|
ed75924e24 | |
|
49ba9a090b | |
|
691e741d70 | |
|
35b8b0def2 | |
|
529c275c0f | |
|
d604f2aab5 | |
|
b0c7e4eed4 | |
|
c6d0256929 | |
|
b74fd270e2 | |
|
4d022883ff | |
|
b595225870 | |
|
fc2593c6ee | |
|
4c0aa4220c | |
|
42621bbf71 | |
|
4c8c2b66f3 | |
|
c6ebab4032 | |
|
3fb276f401 | |
|
bf4ef96a06 | |
|
6ec81a3429 | |
|
00ccf4cb8f | |
|
09da9500b5 | |
|
de7015022f | |
|
e59d165689 | |
|
1075c7ff4a | |
|
4461670e14 | |
|
8e4c32073a | |
|
ac1da17b8d | |
|
9b2ed018bf | |
|
51acbdfd30 | |
|
5ce0aed2ff | |
|
f0c28b8624 | |
|
5f701ccecb | |
|
cfa22d3a1d | |
|
1b83fe6937 | |
|
2ff98a2148 | |
|
30c36baa9c | |
|
bd79025305 | |
|
7c4e9d5823 | |
|
5695bfd645 | |
|
c5f3c72f73 | |
|
7e05b5f680 | |
|
741d4619ee | |
|
7c50b66499 | |
|
96d0897f65 | |
|
c01f3ceff8 | |
|
4023704d31 | |
|
798e9ce1a3 | |
|
6612ffa6d1 | |
|
07100a588c | |
|
0b2d386ca2 | |
|
4b5dd4868b | |
|
f0804fe23b | |
|
97591b1c1d | |
|
b5da7ba233 | |
|
0f52812767 | |
|
0d6c3e44b0 | |
|
60147e3b0f | |
|
f8c64b45a7 | |
|
504912009b | |
|
084916c317 | |
|
073e778a3b | |
|
b5465384ce | |
|
45f96e6537 | |
|
f8fc9fded6 | |
|
f239f862e8 | |
|
872b46d4a5 | |
|
ddfc46a48f | |
|
ad67e2f010 | |
|
9331a766df | |
|
6b10e9c28d | |
|
d15fe37de5 | |
|
5014a2db38 | |
|
f3e885df35 | |
|
98a0eff503 | |
|
6cda9aed1d | |
|
9a464a2fcf | |
|
a4f8ffc3c6 | |
|
23a7896db9 | |
|
e25054117f | |
|
2e4ef09a60 | |
|
717cf77e55 | |
|
ede6fcdfb8 | |
|
6fcb85bca2 | |
|
0cff7c5794 | |
|
9b17d5cd47 | |
|
8ebbd0ac47 | |
|
49f9f7f160 | |
|
22187777e7 | |
|
00b26719f6 | |
|
d6da1824cd | |
|
23d663c3e7 | |
|
1e2b542e4c | |
|
5cd6b22ea4 | |
|
32f02d42ce | |
|
7740dc39ec | |
|
07940bc2c6 | |
|
7c43f2de2c | |
|
39e6ab5247 | |
|
76c7b49142 | |
|
5b418aeccd | |
|
b5fbe0153b | |
|
da7d14e898 | |
|
3aeb971b4d | |
|
dab5c34bad | |
|
596832119b | |
|
6442d99817 | |
|
a7c7715207 | |
|
e3d213e4f1 | |
|
c169b7fbae | |
|
d8e5e4521a | |
|
418670ce33 | |
|
8ddc6e5a20 | |
|
f015a6f2c5 | |
|
7907ba9533 | |
|
1fd3b83ca1 | |
|
35a540f5df | |
|
da6fef6080 | |
|
9a0ebcca06 | |
|
93144322db | |
|
8e832d0aa3 | |
|
02ca59ea7e | |
|
ce226a7f86 | |
|
4ea390897a | |
|
c942d89572 | |
|
d0cc8eca70 | |
|
2e8d20f40a | |
|
5c9091d957 | |
|
1b3f554492 | |
|
67a009ae8d | |
|
4dd69319e5 | |
|
39301f5b59 | |
|
ab8d7f57e9 | |
|
867d6a4069 | |
|
f33dbb2f1b | |
|
1111800383 | |
|
abaeb1cbda | |
|
4f9de487cc | |
|
e15d03a536 | |
|
ad558608ee | |
|
1a612376cb | |
|
a241ef0a2a | |
|
687e1887ee | |
|
5e0947d343 | |
|
1fe71cefca | |
|
88e470c5ac | |
|
2d7599472e | |
|
bb2bfabf9c | |
|
b33ef36ab4 | |
|
ed14564de7 | |
|
9603f82c49 | |
|
52aac3f8b0 | |
|
4f7dd92311 | |
|
265f383f65 | |
|
11b389172c | |
|
dac70a122f | |
|
7a52bc7c6e | |
|
18c515402e | |
|
cda100b3e6 | |
|
63e42f2dd3 | |
|
fd09e7c024 | |
|
d995a4800d | |
|
96754fcf49 | |
|
d1480181b3 | |
|
d6fd83762e | |
|
7d2033db3d | |
|
072c67fd0f | |
|
3e5bda77db | |
|
1510762fbb | |
|
429e66717d | |
|
c129739394 | |
|
43ee0d0672 | |
|
11e9176cb8 | |
|
4d62421446 | |
|
e35c41791b | |
|
b02b92c1c7 | |
|
372ab01d57 | |
|
79e16fb166 | |
|
74e6b9c1b2 | |
|
1413e323f0 | |
|
f09ada2cd2 | |
|
283085cb8d | |
|
5717fc8cfe | |
|
42691c1577 | |
|
cfbeeb3ce9 | |
|
dcca364b78 | |
|
553d2bbb0d | |
|
425dd9fd6a | |
|
c436406e9e | |
|
52e6431d65 | |
|
ddb33e7f35 | |
|
3dcfa708d2 | |
|
aff3678daf | |
|
4356abc820 | |
|
41a5fd087d | |
|
742adccf34 | |
|
97f1464106 | |
|
aef8709ab0 | |
|
0ff1b5ff7d | |
|
d264429726 | |
|
65ba1f8c18 | |
|
48e8415ee4 | |
|
e5a1654341 | |
|
6d1e9ec78f | |
|
fe046027da | |
|
600a0abc72 | |
|
7a87ac924a | |
|
7ce3fa854a | |
|
82e10bb4a4 | |
|
fc3cc96cd8 | |
|
478799965e | |
|
099cd3052a | |
|
ea91ea5ff5 | |
|
6a31eda3c4 | |
|
d74e756b05 | |
|
91ee19f2ab | |
|
c563bf0dd3 | |
|
87d43fc15b | |
|
94942d86f9 | |
|
bfb9bcbbe4 | |
|
f5f23284a3 | |
|
9472527c70 | |
|
6faf78b92e | |
|
1b6c56b2ad | |
|
42358e98eb | |
|
746f0e2753 | |
|
cf7664fb2a | |
|
05d1bc3ae2 | |
|
e9ccdfc191 | |
|
dc080b8566 | |
|
56aba1eaba | |
|
c276525d3a | |
|
fce259d29b | |
|
72575ce2a4 | |
|
2408456d47 | |
|
f2c2d6ce43 | |
|
7f0ab0fee3 | |
|
4236651a09 | |
|
fe85cc1b37 | |
|
d308b8a59e | |
|
cc227e9a66 | |
|
a4682ed9d3 | |
|
d19e83d616 | |
|
9bfc133a67 | |
|
f89ad53235 | |
|
0fbe45073c | |
|
415306d7a8 | |
|
b1e4015630 | |
|
ad97086bf0 | |
|
1d993b85d3 | |
|
46da2e6541 | |
|
d4c2f5b678 | |
|
9b4525e5a7 | |
|
1a31767572 | |
|
74b326caeb | |
|
029dd628b6 | |
|
cf6e4f9de9 | |
|
e47abeaaa5 | |
|
4eee61ab1b | |
|
4202d01630 | |
|
00b5efa484 | |
|
15bb696b59 | |
|
95b6f77848 | |
|
e186b1b9fc | |
|
ede29216f7 | |
|
faeddb84ab | |
|
87f3bcef6f | |
|
f0fae8ce1b | |
|
febb39aef7 | |
|
b93266d1eb | |
|
c3f24b125e | |
|
fcdc6ebb1d | |
|
ec0b8e3b4f | |
|
aa5bbfc9fd | |
|
806342b623 | |
|
307ef33a10 | |
|
f276d5ce83 | |
|
200671b1cf | |
|
46ce99ec18 | |
|
fcc4da3672 | |
|
c93413bae4 | |
|
ac888b1fc4 | |
|
b9bd62bb78 | |
|
1612d737a1 | |
|
7a901b31c4 | |
|
aff06619a0 | |
|
da7faf59a5 | |
|
a5a9a4ea86 | |
|
b481906c86 | |
|
b19b20dad9 | |
|
a9dd45a464 | |
|
bc9e882a37 | |
|
fa477aec83 | |
|
8b2095227c | |
|
6622a72241 | |
|
c964410f7b | |
|
b98b831ae4 | |
|
643e88aef3 | |
|
aff070cdc4 | |
|
955e49fff2 | |
|
7398f7993d | |
|
48b86ebc93 | |
|
bee40965b1 | |
|
fb08a28543 | |
|
4947cbcc9d | |
|
bf3adec727 | |
|
58ade0518e | |
|
56a83615a9 | |
|
73ae599cff | |
|
723b23fa41 | |
|
bf148c6784 | |
|
7fd449724b | |
|
8ebdbf9f6f | |
|
54ab121e89 | |
|
16dcd1e3d4 | |
|
8bd505da36 | |
|
b99491909b | |
|
4de536e2e8 | |
|
8fd29e89d8 | |
|
e7ac873f41 | |
|
ed8f1add35 | |
|
dbe96491f9 | |
|
962a7c8213 | |
|
3493759998 | |
|
b6a6b8a81e | |
|
cbb28212d6 | |
|
40b5ecfe69 | |
|
fafb313f7d | |
|
d31d7770aa | |
|
30a070dca0 | |
|
0e618430ff | |
|
9db61a7190 | |
|
b9a6da957d | |
|
2dbed1215d | |
|
12e09f04aa | |
|
97ec076ec1 | |
|
4a86d5d441 | |
|
aebacbccaf | |
|
74bb33052c | |
|
e42d7a6e0b | |
|
95007d06a2 | |
|
41553dd0f9 | |
|
8adab68cdc | |
|
f110718342 | |
|
deee2ba59f | |
|
be12b1fd30 | |
|
f07a429d8b | |
|
20f3170fe5 | |
|
f58f5ae95f | |
|
625094f0e3 | |
|
b83e703cf1 | |
|
5f50e1f082 | |
|
a342ecca66 | |
|
bacd292fcf | |
|
c3bf062da9 | |
|
2653902dad | |
|
c0bc1b431a | |
|
fb444c03b5 | |
|
1914641b77 | |
|
92ba4af306 | |
|
af8e982cc9 | |
|
15eea45aa9 | |
|
5f7434d24f | |
|
448ad1bda4 | |
|
ca92abea68 | |
|
a051fe511f | |
|
4e4d19aed7 | |
|
c9f5d11413 | |
|
d306bc915c | |
|
4c98b5c828 | |
|
709a5c1560 | |
|
a1277522c2 | |
|
52350b2325 | |
|
9e125e37d3 | |
|
db1128ab52 | |
|
371c7afb25 | |
|
88175a93c0 | |
|
e0d4265875 | |
|
8b08c35b96 | |
|
67addbe7ab | |
|
5f736c0af4 | |
|
48d3952e3c | |
|
374d08e6ea | |
|
e3b735ced3 | |
|
4565205aad | |
|
cb5e50792a | |
|
fc73859f8f | |
|
c1d5e52a10 | |
|
df0806efa9 | |
|
a6a910c909 | |
|
1373d1d690 | |
|
bab6593fba | |
|
c209fa9249 | |
|
2c76710f91 | |
|
4627382c91 | |
|
d50ba3ac6e | |
|
0f74f6ac7c | |
|
a2406c667a | |
|
a2ab93bd46 | |
|
c128fa2871 | |
|
116cb46fcd | |
|
d121a90dcc | |
|
5b0d221daa | |
|
38b52d0618 | |
|
ce6e450b44 | |
|
f1ca18b4a5 | |
|
2f05a3d21e | |
|
f4afcaf8cc | |
|
95da651d6d | |
|
0577b53517 | |
|
88c1e6d72d | |
|
077a5cd997 |
|
@ -1,2 +1,14 @@
|
|||
*.DS_Store
|
||||
dist/
|
||||
.AppleDouble
|
||||
*.Parent
|
||||
|
||||
node_modules
|
||||
dist
|
||||
|
||||
*.svd
|
||||
*debug_custom.json
|
||||
*debug.cfg
|
||||
|
||||
notes/mphd
|
||||
|
||||
./lib
|
|
@ -0,0 +1,9 @@
|
|||
[submodule "scad/common"]
|
||||
path = scad/common
|
||||
url = https://git.sixteenmillimeter.com/modules/common.git
|
||||
[submodule "scad/sprocketed_roller"]
|
||||
path = scad/sprocketed_roller
|
||||
url = https://git.sixteenmillimeter.com/modules/sprocketed_roller.git
|
||||
[submodule "scad/MCAD"]
|
||||
path = scad/MCAD
|
||||
url = https://github.com/openscad/MCAD.git
|
|
@ -0,0 +1,7 @@
|
|||
Copyright 2018-2021 M McWilliams
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
149
Readme.md
149
Readme.md
|
@ -1,56 +1,93 @@
|
|||
# mcopy
|
||||
|
||||
An open platform for controlling small-gauge film optical printers (16mm, Super8, 8mm).
|
||||
|
||||
-------
|
||||
1. <a href="#intro">Introduction</a>
|
||||
2. <a href="#download"></a>
|
||||
2. <a href="#software">Software</a>
|
||||
3. <a href="#firmware">Firmware</a>
|
||||
3. <a href="#hardware">Hardware</a>
|
||||
4. <a href="#why">Why?</a>
|
||||
|
||||
-------
|
||||
|
||||
## Introduction <a name="intro"></a>
|
||||
|
||||
The `mcopy` project is comprised of software and hardware for optical printers, built with re-purposed broken projectors.
|
||||
|
||||
## Downloads
|
||||
|
||||
|
||||
#### Components
|
||||
|
||||
* Sequencer desktop app
|
||||
* Scripting language, called mscript, for complex sequences
|
||||
* Arduino firmware for projectors, cameras, lights and existing printers
|
||||
* 3D models of parts
|
||||
|
||||
## Software <a name="software"></a>
|
||||
|
||||
The mcopy desktop app is an Electron-based project which can be built for Linux, Windows and Mac.
|
||||
|
||||
## Firmware <a name="firmware"></a>
|
||||
|
||||
This project contains Arduino formware for controlling:
|
||||
|
||||
* projector
|
||||
* camera (see [intval2](https://github.com/sixteenmillimeter/intval2.git) for more info)
|
||||
* light
|
||||
* projector + camera
|
||||
* projector + light
|
||||
* camera + light
|
||||
* projector + camera + light
|
||||
|
||||
Using a simple interface, this modular platform can be used to control custom-built and modified legacy optical printers.
|
||||
|
||||
|
||||
## Hardware <a name="hardware"></a>
|
||||
|
||||
All hardware for this project is available as plaintext OpenSCAD files and 3D print-able .STL files. The hardware component of this project is aimed at modifying broken Bell & Howell projectors into USB serial-controlled projectors to be used in optical printing.
|
||||
|
||||
|
||||
## Why? <a name="why"></a>
|
||||
|
||||
I'm interested in expanding the viability and access of the 16mm film format and to repurpose thre rising tide of discarded film technology.
|
||||
|
||||
# mcopy
|
||||
|
||||
An open platform for controlling small-gauge film optical printers (16mm, Super8, 8mm).
|
||||
|
||||
## [Project Home - git.sixteenmillimeter.com/16mm/mcopy](https://git.sixteenmillimeter.com/16mm/mcopy)
|
||||
|
||||
* Github Mirror - [github.com/sixteenmillimeter/mcopy](https://github.com/sixteenmillimeter/mcopy)
|
||||
* Gitlab Mirror - [gitlab.com/16mm/mcopy](https://gitlab.com/16mm/mcopy)
|
||||
|
||||
-------
|
||||
1. <a href="#intro">Introduction</a>
|
||||
2. <a href="#downloads">Downloads</a>
|
||||
1. <a href="#usage">Usage</a>
|
||||
2. <a href="#software">Software</a>
|
||||
3. <a href="#firmware">Firmware</a>
|
||||
3. <a href="#hardware">Hardware</a>
|
||||
4. <a href="#why">Why?</a>
|
||||
|
||||
-------
|
||||
|
||||
## Introduction <a name="intro"></a>
|
||||
|
||||
The `mcopy` project is comprised of software and hardware for optical printers, built with re-purposed broken projectors.
|
||||
|
||||
#### Components
|
||||
|
||||
* Sequencer desktop app
|
||||
* Scripting language, called `mscript`, for orchestrating complex sequences
|
||||
* Arduino firmware for projectors, cameras, lights and existing printers
|
||||
* 3D models of parts used for modifying projectors and printers
|
||||
* Schematics for simple Arduino-based electronics
|
||||
* Filmout feature for digitally transferring video and images to analog film
|
||||
* Interoperability with the [intval3](https://github.com/sixteenmillimeter/intval3) intervalometer
|
||||
|
||||
## Downloads <a name="downloads"></a>
|
||||
|
||||
### Latest Installers
|
||||
|
||||
* [1.6.9](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.6.9) for macOS, Linux (.deb) and Windows (.msi)
|
||||
|
||||
### Older Versions
|
||||
* [1.6.7](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.6.7) for macOS and Linux (.deb)
|
||||
* [1.6.4](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.6.4) for macOS, Linux (.deb) and Windows (.msi)
|
||||
* [1.6.2](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.6.2) for macOS
|
||||
* [1.6.1](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.6.1) for macOS
|
||||
* [1.5.2](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.5.2) for macOS
|
||||
* [1.4.9](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.4.9) for macOS and Linux (.deb)
|
||||
* [1.2.0](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.2.0) for macOS and Linux (.deb)
|
||||
* [1.0.3](https://github.com/sixteenmillimeter/mcopy/releases/tag/1.0.3) for macOS and Linux (.deb)
|
||||
|
||||
For Windows, you can [install from source](https://github.com/sixteenmillimeter/mcopy/tree/master/app#mcopy-desktop-app) for now.
|
||||
|
||||
## Usage <a name="usage"></a>
|
||||
|
||||
The software requires your hardware to be in place before the mcopy control app is useful.
|
||||
|
||||
![mcopy app](docs/mcopy.png?raw=true "mcopy app")
|
||||
|
||||
## Software <a name="software"></a>
|
||||
|
||||
The mcopy desktop app is an Electron-based project which can be built for Linux, Windows and macOS.
|
||||
Pre-built packages will be made available for macOS, initially, with the other two target platforms to follow.
|
||||
To build the desktop app from source, see the [installation and running instructions](https://github.com/sixteenmillimeter/mcopy/tree/master/app#mcopy-desktop-app).
|
||||
The desktop software also interoperates with two related projects; the Bluetooth + Wifi capable, Raspberry Pi-based [INTVAL3](https://github.com/sixteenmillimeter/intval3) and the Arduino-based [intval2](https://github.com/sixteenmillimeter/intval2).
|
||||
|
||||
## Firmware <a name="firmware"></a>
|
||||
|
||||
This project contains Arduino formware for controlling:
|
||||
|
||||
* a projector
|
||||
* a camera (see [intval2](https://github.com/sixteenmillimeter/intval2) for more info)
|
||||
* a light
|
||||
* a projector + a camera
|
||||
* a projector + a light
|
||||
* a camera + a light
|
||||
* a camera + a projector + a light
|
||||
|
||||
Using a simple serial interface, this modular platform can be used to control DIY components, modified existing optical printers or a mixture of components.
|
||||
The desktop app can connect to multiple serial devices, so your mcopy optical printer can be built from various designs that suit your hardware tastes/needs/available parts.
|
||||
|
||||
|
||||
## Hardware <a name="hardware"></a>
|
||||
|
||||
All non-electronic hardware for this project is available as plaintext OpenSCAD files and 3D print-able .STL files.
|
||||
The hardware component of this project is aimed at modifying broken Bell & Howell projectors into USB serial-controlled projectors to be used in optical printing.
|
||||
|
||||
As a secondary capability, this desktop software and firmware package can be used to replace the sequencers for early-model JK optical printers, with some modification.
|
||||
|
||||
|
||||
## Why? <a name="why"></a>
|
||||
|
||||
I'm interested in expanding the viability and access of the 16mm film format and to repurpose thre rising tide of discarded film technology.
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
node_modules/*
|
||||
logs/*
|
||||
data/transfer*.json
|
||||
data/transfer*.json
|
||||
.appleId*
|
||||
.applePwd*
|
||||
.appleIdentity*
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
# mcopy desktop app
|
||||
|
||||
1. Installation
|
||||
|
||||
------
|
||||
|
||||
## Installation
|
||||
|
||||
The mcopy desktop app can be either [installed from a binary (on macOS)](https://github.com/sixteenmillimeter/mcopy/releases) or built from source on any platform that supports node.js and [Electron apps](https://electronjs.org/).
|
||||
|
||||
### Dependencies
|
||||
|
||||
* git
|
||||
* [node.js](https://nodejs.org/en/)
|
||||
|
||||
Once `node` is installed (see below for platform-specific instructions) open your terminal application and enter the following commands:
|
||||
|
||||
```
|
||||
git clone https://github.com/sixteenmillimeter/mcopy.git
|
||||
cd mcopy/app
|
||||
npm install
|
||||
```
|
||||
|
||||
That's it. Once the `npm install` process is complete, the app can be launched with:
|
||||
|
||||
```
|
||||
npm start
|
||||
```
|
||||
|
||||
If you are interested in running in dev mode, simply use:
|
||||
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### macOS
|
||||
|
||||
#### Installing node.js on macOS
|
||||
|
||||
The node.js runtime can be easily installed on macOS if you already have [Homebrew](https://brew.sh/).
|
||||
Simply install node.js with the command:
|
||||
```
|
||||
brew install node
|
||||
```
|
||||
|
||||
If you're not using Homebrew, you can also install it from the [node.js website](https://nodejs.org/en/download/).
|
||||
|
||||
### Linux
|
||||
|
||||
#### Installing node.js on Linux
|
||||
|
||||
See this helpful document from the [node.js Foundation](https://nodejs.org/en/download/package-manager/) about installing node.js from different package managers.
|
||||
This will provide more detailed instructions about distro-specific dependencies for node.js and the different packages available.
|
||||
Use a more current version of node, if available.
|
||||
At the time of this writing, development is taking place on node.js version `9.7.1`.
|
||||
|
||||
#### Arduino firmware
|
||||
|
||||
It's recommended that on linux distributions, you have the Arduino IDE installed for debugging and to ensure that your system serial permissions are configured to communicate with the Arduino devices.
|
||||
|
||||
#### Binary installation
|
||||
|
||||
When installing from the pre-built .deb package, you may have to locate the package after installation using the following command:
|
||||
```
|
||||
dpkg -L mcopy-app
|
||||
```
|
||||
|
||||
In the output, you should see an item like `/usr/lib/mcopy-app/mcopy` which is the binary that contains the desktop app. I will improve the Linux build process, but will also accept any PRs which improve it as well.
|
||||
|
||||
### Windows
|
||||
|
||||
#### Installing node.js on Windows
|
||||
|
||||
Install node.js on Windows using one of their [many install options](https://nodejs.org/en/download/).
|
|
@ -1,6 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
#package app
|
||||
./node_modules/.bin/electron-packager . mcopy --overwrite --asar=true --platform=linux --arch=x64 --icon=assets/icons/icon.png --prune=true --out=../dist
|
||||
#build a .deb installer
|
||||
./node_modules/.bin/electron-installer-debian --src ../dist/mcopy-linux-x64/ --dest ../dist/installers/ --arch amd64
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
./node_modules/.bin/electron-packager . --overwrite --platform=darwin --arch=x64 --icon=assets/icons/icon.icns --prune=true --out=../dist
|
||||
#build dmg for mac install
|
||||
sleep 5s
|
||||
mkdir ../dist/installers
|
||||
./node_modules/.bin/electron-installer-dmg ../dist/mcopy-darwin-x64/mcopy.app mcopy --out=../dist/installers --icon=assets/icons/icon.icns --overwrite
|
||||
# Path to the icon file that will be the app icon in the DMG window.
|
||||
# --icon-size=<px> How big to make the icon for the app in the DMG. [Default: `80`].
|
||||
# --background=<path> Path to a PNG image to use as the background of the DMG.
|
||||
#--overwrite Overwrite any existing DMG.
|
|
@ -1,18 +0,0 @@
|
|||
const { MSICreator } = require('electron-wix-msi');
|
||||
|
||||
// Step 1: Instantiate the MSICreator
|
||||
const msiCreator = new MSICreator({
|
||||
appDirectory: '../dist/mcopy-win32-x64',
|
||||
description: 'mcopy optical printer GUI',
|
||||
exe: 'mcopy',
|
||||
name: 'mcopy',
|
||||
manufacturer: 'sixteenmillimeter.com',
|
||||
version: '2.0.0',
|
||||
outputDirectory: '../dist/'
|
||||
});
|
||||
|
||||
// Step 2: Create a .wxs template file
|
||||
msiCreator.create();
|
||||
|
||||
// Step 3: Compile the template to a .msi file
|
||||
setTimeout(msiCreator.compile, 30000)
|
|
@ -1,7 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
./node_modules/.bin/electron-packager . mcopy --overwrite --asar=true --platform=win32 --arch=x64 --icon=assets/icons/win/icon.ico --prune=true --out=../dist --version-string.CompanyName="sixteenmillimeter.com" --version-string.FileDescription="Open Source Optical Printer Platform" --version-string.ProductName="mcopy"
|
||||
|
||||
mkdir ../dist/installers
|
||||
|
||||
node ./build_win.js
|
527
app/css/app.css
527
app/css/app.css
|
@ -194,8 +194,8 @@ button:focus {
|
|||
width: 66px;
|
||||
height: 66px;
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
left: 7px;
|
||||
top: 14px / 2;
|
||||
left: 14px / 2;
|
||||
}
|
||||
.dial-wrapper input {
|
||||
margin-top: 94px;
|
||||
|
@ -210,10 +210,10 @@ button:focus {
|
|||
top: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
width: 40px;
|
||||
width: 80px / 2;
|
||||
}
|
||||
.dial-container.dial-container1 {
|
||||
left: 40px;
|
||||
left: 80px / 2;
|
||||
}
|
||||
.dial-container.dial-container1 .dial-wedge {
|
||||
transform: rotateZ(0deg);
|
||||
|
@ -227,19 +227,19 @@ button:focus {
|
|||
.dial-container.dial-container2 .dial-wedge {
|
||||
transform: rotateZ(0deg);
|
||||
border-radius: 80px 0 0 80px;
|
||||
transform-origin: 40px 40px;
|
||||
transform-origin: 80px/2 80px/2;
|
||||
}
|
||||
.dial-wedge {
|
||||
height: 80px;
|
||||
width: 40px;
|
||||
width: 80px / 2;
|
||||
}
|
||||
.dial-marker {
|
||||
border-radius: 50%;
|
||||
height: 7px;
|
||||
width: 7px;
|
||||
height: 14px / 2;
|
||||
width: 14px / 2;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(22%);
|
||||
left: calc(50% - (14px * 2));
|
||||
}
|
||||
.dial-end {
|
||||
transform: rotateZ(0deg);
|
||||
|
@ -367,6 +367,7 @@ button:focus {
|
|||
float: right;
|
||||
width: 90px;
|
||||
margin-right: 60px;
|
||||
height: 32px;
|
||||
}
|
||||
#seq_stats {
|
||||
width: 40%;
|
||||
|
@ -381,16 +382,16 @@ button:focus {
|
|||
font-weight: 600;
|
||||
float: right;
|
||||
}
|
||||
#seq_loop {
|
||||
#seq_loop_wrap {
|
||||
width: 40%;
|
||||
float: left;
|
||||
padding: 0 0 0 56px;
|
||||
}
|
||||
#seq_loop h3 {
|
||||
#seq_loop_wrap h3 {
|
||||
font-size: 20px;
|
||||
margin: 12px 0 3px;
|
||||
}
|
||||
#seq_loop input {
|
||||
#seq_loop_wrap input {
|
||||
font-family: 'Menlo', monospace;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: #fff;
|
||||
|
@ -402,48 +403,91 @@ button:focus {
|
|||
#sequence {
|
||||
width: 970px;
|
||||
padding-bottom: 21px;
|
||||
padding-left: 70px;
|
||||
padding-left: 92px;
|
||||
}
|
||||
#sequence #cam_forward,
|
||||
#sequence #proj_forward,
|
||||
#sequence #camera_forward,
|
||||
#sequence #camera_second_forward,
|
||||
#sequence #projector_forward,
|
||||
#sequence #projector_second_forward,
|
||||
#sequence #black_forward {
|
||||
clear: both;
|
||||
}
|
||||
#sequence #cam_forward input[type=checkbox],
|
||||
#sequence #proj_forward input[type=checkbox],
|
||||
#sequence #camera_forward input[type=checkbox],
|
||||
#sequence #camera_second_forward input[type=checkbox],
|
||||
#sequence #projector_forward input[type=checkbox],
|
||||
#sequence #projector_second_forward input[type=checkbox],
|
||||
#sequence #black_forward input[type=checkbox] {
|
||||
border: 2px solid #00C4A0;
|
||||
}
|
||||
#sequence #cam_forward input[type=checkbox]:checked,
|
||||
#sequence #proj_forward input[type=checkbox]:checked,
|
||||
#sequence #camera_forward input[type=checkbox]:checked,
|
||||
#sequence #camera_second_forward input[type=checkbox]:checked,
|
||||
#sequence #projector_forward input[type=checkbox]:checked,
|
||||
#sequence #projector_second_forward input[type=checkbox]:checked,
|
||||
#sequence #black_forward input[type=checkbox]:checked {
|
||||
background: #00C4A0;
|
||||
}
|
||||
#sequence #cam_forward > div,
|
||||
#sequence #proj_forward > div,
|
||||
#sequence #camera_forward > div,
|
||||
#sequence #camera_second_forward > div,
|
||||
#sequence #projector_forward > div,
|
||||
#sequence #projector_second_forward > div,
|
||||
#sequence #black_forward > div {
|
||||
color: #00C4A0;
|
||||
}
|
||||
#sequence #cam_backward,
|
||||
#sequence #proj_backward,
|
||||
#sequence #camera_backward,
|
||||
#sequence #camera_second_backward,
|
||||
#sequence #projector_backward,
|
||||
#sequence #projector_second_backward,
|
||||
#sequence #black_backward {
|
||||
clear: both;
|
||||
}
|
||||
#sequence #cam_backward input[type=checkbox],
|
||||
#sequence #proj_backward input[type=checkbox],
|
||||
#sequence #camera_backward input[type=checkbox],
|
||||
#sequence #camera_second_backward input[type=checkbox],
|
||||
#sequence #projector_backward input[type=checkbox],
|
||||
#sequence #projector_second_backward input[type=checkbox],
|
||||
#sequence #black_backward input[type=checkbox] {
|
||||
border: 2px solid #AB1A25;
|
||||
}
|
||||
#sequence #cam_backward input[type=checkbox]:checked,
|
||||
#sequence #proj_backward input[type=checkbox]:checked,
|
||||
#sequence #camera_backward input[type=checkbox]:checked,
|
||||
#sequence #camera_second_backward input[type=checkbox]:checked,
|
||||
#sequence #projector_backward input[type=checkbox]:checked,
|
||||
#sequence #projector_second_backward input[type=checkbox]:checked,
|
||||
#sequence #black_backward input[type=checkbox]:checked {
|
||||
background: #AB1A25;
|
||||
}
|
||||
#sequence #cam_backward > div,
|
||||
#sequence #proj_backward > div,
|
||||
#sequence #camera_backward > div,
|
||||
#sequence #camera_second_backward > div,
|
||||
#sequence #projector_backward > div,
|
||||
#sequence #projector_second_backward > div,
|
||||
#sequence #black_backward > div {
|
||||
color: #AB1A25;
|
||||
}
|
||||
#sequence #camera_second_forward input[type=checkbox],
|
||||
#sequence #projector_second_forward input[type=checkbox] {
|
||||
border: 2px solid #14d8b4;
|
||||
}
|
||||
#sequence #camera_second_forward input[type=checkbox]:checked,
|
||||
#sequence #projector_second_forward input[type=checkbox]:checked {
|
||||
background: #14d8b4;
|
||||
}
|
||||
#sequence #camera_second_forward > div,
|
||||
#sequence #projector_second_forward > div {
|
||||
color: #14d8b4;
|
||||
}
|
||||
#sequence #camera_second_backward input[type=checkbox],
|
||||
#sequence #projector_second_backward input[type=checkbox] {
|
||||
border: 2px solid #bf2e39;
|
||||
}
|
||||
#sequence #camera_second_backward input[type=checkbox]:checked,
|
||||
#sequence #projector_second_backward input[type=checkbox]:checked {
|
||||
background: #bf2e39;
|
||||
}
|
||||
#sequence #camera_second_backward > div,
|
||||
#sequence #projector_second_backward > div {
|
||||
color: #bf2e39;
|
||||
}
|
||||
#sequence #black input[type=checkbox]:checked {
|
||||
background: white;
|
||||
}
|
||||
#sequence input[type=checkbox] {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
@ -460,6 +504,10 @@ button:focus {
|
|||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
}
|
||||
#sequence input[type=checkbox].disabled {
|
||||
cursor: not-allowed;
|
||||
border-color: #646464;
|
||||
}
|
||||
#sequence .L {
|
||||
display: inline-block;
|
||||
width: 35px;
|
||||
|
@ -504,10 +552,10 @@ button:focus {
|
|||
font-family: 'Menlo', monospace;
|
||||
background-color: #272b30;
|
||||
position: absolute;
|
||||
top: 128px;
|
||||
top: 113px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 15px;
|
||||
width: 54px;
|
||||
width: 75px;
|
||||
}
|
||||
#seq_labels div {
|
||||
height: 43px;
|
||||
|
@ -518,16 +566,41 @@ button:focus {
|
|||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
#seq_labels i.fa {
|
||||
right: 3px;
|
||||
position: absolute;
|
||||
margin-top: 10px;
|
||||
}
|
||||
#loop_current {
|
||||
margin-top: 54px;
|
||||
width: 121px;
|
||||
font-family: 'Menlo', monospace;
|
||||
font-size: 22px;
|
||||
margin-top: 13px;
|
||||
margin-right: 50px;
|
||||
width: 93px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
float: right;
|
||||
color: #DAE035;
|
||||
}
|
||||
#buttons > div {
|
||||
#seq_pause {
|
||||
display: none;
|
||||
}
|
||||
#seq_progress {
|
||||
width: 100%;
|
||||
height: 15px;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
#buttons > div,
|
||||
#buttons_2 > div {
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
#buttons .proj2,
|
||||
#buttons_2 .proj2 {
|
||||
float: right !important;
|
||||
}
|
||||
.cmd {
|
||||
width: 240px;
|
||||
text-align: center;
|
||||
|
@ -562,6 +635,11 @@ button:focus {
|
|||
background: #AB1A25;
|
||||
border-color: #AB1A25;
|
||||
}
|
||||
.cmd:active.capper,
|
||||
.cmd.active.capper {
|
||||
background: white;
|
||||
color: #272b30;
|
||||
}
|
||||
.cmd:active i,
|
||||
.cmd.active i {
|
||||
color: #272b30;
|
||||
|
@ -585,14 +663,44 @@ button:focus {
|
|||
::-webkit-scrollbar-thumb:window-inactive {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
#settings h4 {
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
#settings > div {
|
||||
width: 300px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#settings > div.left {
|
||||
float: left;
|
||||
padding-left: 30px;
|
||||
}
|
||||
#settings > div.right {
|
||||
float: right;
|
||||
padding-right: 30px;
|
||||
}
|
||||
#settings > div.right input[type=number] {
|
||||
min-width: 200px;
|
||||
width: 200px;
|
||||
}
|
||||
#settings > div.right input[readonly] {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
#settings > div.right .spacer {
|
||||
height: 62px;
|
||||
}
|
||||
#settings > div.right .proj_time {
|
||||
height: 111px;
|
||||
}
|
||||
#settings > div.right .cam_time {
|
||||
height: 111px;
|
||||
}
|
||||
#settings > div.right > div {
|
||||
width: 270px;
|
||||
}
|
||||
#settings > div > div {
|
||||
width: 360px;
|
||||
}
|
||||
#settings input[type=text],
|
||||
#settings input[type=number],
|
||||
#settings select {
|
||||
display: block;
|
||||
border-radius: 5px;
|
||||
|
@ -607,33 +715,43 @@ button:focus {
|
|||
padding: 6px 12px;
|
||||
font-size: 21px;
|
||||
min-width: 300px;
|
||||
max-width: 300px;
|
||||
}
|
||||
#settings input[type=text] span,
|
||||
#settings input[type=number] span,
|
||||
#settings select span {
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
font-weight: 200;
|
||||
}
|
||||
#settings input[type=text]:active,
|
||||
#settings input[type=number]:active,
|
||||
#settings select:active,
|
||||
#settings input[type=text] .active,
|
||||
#settings input[type=number] .active,
|
||||
#settings select .active {
|
||||
background: #fff;
|
||||
color: #272b30;
|
||||
outline: none;
|
||||
}
|
||||
#settings input[type=text]:focus,
|
||||
#settings input[type=number]:focus,
|
||||
#settings select:focus {
|
||||
outline: none;
|
||||
}
|
||||
#settings input[type=text].active,
|
||||
#settings input[type=number].active,
|
||||
#settings select.active {
|
||||
border-color: #DAE035;
|
||||
color: #DAE035;
|
||||
}
|
||||
#settings input[type=text] {
|
||||
width: 200px;
|
||||
}
|
||||
#settings button {
|
||||
margin-top: -1px;
|
||||
margin-top: 0px;
|
||||
float: right;
|
||||
padding: 8px 16px 9px;
|
||||
}
|
||||
#settings input[type=radio] {
|
||||
float: right;
|
||||
|
@ -642,6 +760,17 @@ button:focus {
|
|||
#settings .spacer {
|
||||
margin-top: 10px;
|
||||
}
|
||||
#settings #version {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
bottom: 10px;
|
||||
z-index: 1000;
|
||||
height: 14px;
|
||||
width: auto;
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
color: #999;
|
||||
}
|
||||
.cm-s-monokai.CodeMirror {
|
||||
background: #272b30 !important;
|
||||
}
|
||||
|
@ -674,10 +803,148 @@ button:focus {
|
|||
background: black;
|
||||
color: #fff;
|
||||
}
|
||||
#log {
|
||||
position: fixed;
|
||||
#video input,
|
||||
#video select {
|
||||
display: block;
|
||||
border-radius: 5px;
|
||||
border: 2px solid #fff;
|
||||
text-align: center;
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
padding: 8px 0;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
font-size: 21px;
|
||||
min-width: 300px;
|
||||
}
|
||||
#video input span,
|
||||
#video select span {
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
font-weight: 200;
|
||||
}
|
||||
#video input:active,
|
||||
#video select:active,
|
||||
#video input .active,
|
||||
#video select .active {
|
||||
background: #fff;
|
||||
color: #272b30;
|
||||
outline: none;
|
||||
}
|
||||
#video input:focus,
|
||||
#video select:focus {
|
||||
outline: none;
|
||||
}
|
||||
#video input.active,
|
||||
#video select.active {
|
||||
border-color: #DAE035;
|
||||
color: #DAE035;
|
||||
}
|
||||
#video button,
|
||||
#video select {
|
||||
padding: 9px 16px 8px;
|
||||
}
|
||||
#path_bar {
|
||||
padding: 5px;
|
||||
height: 50px;
|
||||
}
|
||||
#path_bar input {
|
||||
float: left;
|
||||
}
|
||||
#path_bar button {
|
||||
float: left;
|
||||
margin-left: 5px;
|
||||
}
|
||||
#path_bar select {
|
||||
line-height: 41px;
|
||||
height: 37px;
|
||||
margin-right: 5px;
|
||||
float: right;
|
||||
box-sizing: content-box;
|
||||
padding: 0 0 0 8px;
|
||||
}
|
||||
#filmout_monitor {
|
||||
display: none;
|
||||
border: 2px solid white;
|
||||
box-sizing: border-box;
|
||||
height: 360px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
#filmout_monitor.on {
|
||||
display: block;
|
||||
}
|
||||
#filmout_preview_wrap {
|
||||
background: #000;
|
||||
width: 100%;
|
||||
height: 160px;
|
||||
height: 360px;
|
||||
}
|
||||
#filmout {
|
||||
position: absolute;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: block;
|
||||
opacity: 0;
|
||||
}
|
||||
#filmout.on {
|
||||
opacity: 1;
|
||||
}
|
||||
#filmout_position_wrap {
|
||||
padding-top: 5px;
|
||||
height: 50px;
|
||||
}
|
||||
#filmout_position_wrap input {
|
||||
margin-right: 5px;
|
||||
margin-left: 5px;
|
||||
width: 308px !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
#filmout_position_wrap button,
|
||||
#filmout_position_wrap input {
|
||||
float: left;
|
||||
}
|
||||
#filmout_position_wrap > div {
|
||||
width: 425px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#filmout_functions {
|
||||
padding-top: 5px;
|
||||
}
|
||||
#filmout_functions > div {
|
||||
width: 425px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#filmout_stats_video,
|
||||
#filmout_stats_monitor {
|
||||
width: 150px;
|
||||
position: absolute;
|
||||
padding: 10px 5px;
|
||||
text-align: center;
|
||||
}
|
||||
#filmout_stats_video h3,
|
||||
#filmout_stats_monitor h3 {
|
||||
font-size: 20px;
|
||||
margin: 16px 0 3px;
|
||||
text-align: center;
|
||||
}
|
||||
#filmout_stats_video {
|
||||
left: 5px;
|
||||
}
|
||||
#filmout_stats_monitor {
|
||||
right: 5px;
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
.show {
|
||||
display: block;
|
||||
}
|
||||
#screens {
|
||||
overflow-x: hidden;
|
||||
|
@ -733,29 +1000,71 @@ button:focus {
|
|||
}
|
||||
#counters .cam,
|
||||
#counters_2 .cam,
|
||||
#counters_3 .cam,
|
||||
#move_to .cam,
|
||||
#move_to_2 .cam,
|
||||
#counters .cam2,
|
||||
#counters_2 .cam2,
|
||||
#counters_3 .cam2,
|
||||
#move_to .cam2,
|
||||
#move_to_2 .cam2,
|
||||
#counters .proj,
|
||||
#counters_2 .proj,
|
||||
#move_to .proj {
|
||||
#counters_3 .proj,
|
||||
#move_to .proj,
|
||||
#move_to_2 .proj,
|
||||
#counters .proj2,
|
||||
#counters_2 .proj2,
|
||||
#counters_3 .proj2,
|
||||
#move_to .proj2,
|
||||
#move_to_2 .proj2 {
|
||||
width: 50%;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
#counters .cam label,
|
||||
#counters_2 .cam label,
|
||||
#counters_3 .cam label,
|
||||
#move_to .cam label,
|
||||
#move_to_2 .cam label,
|
||||
#counters .cam2 label,
|
||||
#counters_2 .cam2 label,
|
||||
#counters_3 .cam2 label,
|
||||
#move_to .cam2 label,
|
||||
#move_to_2 .cam2 label,
|
||||
#counters .proj label,
|
||||
#counters_2 .proj label,
|
||||
#move_to .proj label {
|
||||
#counters_3 .proj label,
|
||||
#move_to .proj label,
|
||||
#move_to_2 .proj label,
|
||||
#counters .proj2 label,
|
||||
#counters_2 .proj2 label,
|
||||
#counters_3 .proj2 label,
|
||||
#move_to .proj2 label,
|
||||
#move_to_2 .proj2 label {
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
display: block;
|
||||
}
|
||||
#counters .cam input,
|
||||
#counters_2 .cam input,
|
||||
#counters_3 .cam input,
|
||||
#move_to .cam input,
|
||||
#move_to_2 .cam input,
|
||||
#counters .cam2 input,
|
||||
#counters_2 .cam2 input,
|
||||
#counters_3 .cam2 input,
|
||||
#move_to .cam2 input,
|
||||
#move_to_2 .cam2 input,
|
||||
#counters .proj input,
|
||||
#counters_2 .proj input,
|
||||
#move_to .proj input {
|
||||
#counters_3 .proj input,
|
||||
#move_to .proj input,
|
||||
#move_to_2 .proj input,
|
||||
#counters .proj2 input,
|
||||
#counters_2 .proj2 input,
|
||||
#counters_3 .proj2 input,
|
||||
#move_to .proj2 input,
|
||||
#move_to_2 .proj2 input {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: #fff;
|
||||
padding: 6px 12px;
|
||||
|
@ -767,44 +1076,147 @@ button:focus {
|
|||
}
|
||||
#counters .cam input.changed,
|
||||
#counters_2 .cam input.changed,
|
||||
#counters_3 .cam input.changed,
|
||||
#move_to .cam input.changed,
|
||||
#move_to_2 .cam input.changed,
|
||||
#counters .cam2 input.changed,
|
||||
#counters_2 .cam2 input.changed,
|
||||
#counters_3 .cam2 input.changed,
|
||||
#move_to .cam2 input.changed,
|
||||
#move_to_2 .cam2 input.changed,
|
||||
#counters .proj input.changed,
|
||||
#counters_2 .proj input.changed,
|
||||
#move_to .proj input.changed {
|
||||
#counters_3 .proj input.changed,
|
||||
#move_to .proj input.changed,
|
||||
#move_to_2 .proj input.changed,
|
||||
#counters .proj2 input.changed,
|
||||
#counters_2 .proj2 input.changed,
|
||||
#counters_3 .proj2 input.changed,
|
||||
#move_to .proj2 input.changed,
|
||||
#move_to_2 .proj2 input.changed {
|
||||
color: #DAE035;
|
||||
}
|
||||
#counters .cam,
|
||||
#counters_2 .cam,
|
||||
#move_to .cam {
|
||||
#counters_3 .cam,
|
||||
#move_to .cam,
|
||||
#move_to_2 .cam,
|
||||
#counters .cam2,
|
||||
#counters_2 .cam2,
|
||||
#counters_3 .cam2,
|
||||
#move_to .cam2,
|
||||
#move_to_2 .cam2 {
|
||||
float: left;
|
||||
}
|
||||
#counters .proj,
|
||||
#counters_2 .proj,
|
||||
#move_to .proj {
|
||||
#counters_3 .proj,
|
||||
#move_to .proj,
|
||||
#move_to_2 .proj,
|
||||
#counters .proj2,
|
||||
#counters_2 .proj2,
|
||||
#counters_3 .proj2,
|
||||
#move_to .proj2,
|
||||
#move_to_2 .proj2 {
|
||||
float: right;
|
||||
}
|
||||
#move_to {
|
||||
#counters.projectors .proj,
|
||||
#counters.projectors .proj2 {
|
||||
width: 25%;
|
||||
}
|
||||
#counters.projectors .proj label,
|
||||
#counters.projectors .proj2 label {
|
||||
line-height: 34px;
|
||||
font-size: 18px;
|
||||
}
|
||||
#counters.projectors .proj input,
|
||||
#counters.projectors .proj2 input {
|
||||
width: 90%;
|
||||
}
|
||||
#counters.cameras .cam,
|
||||
#counters.cameras .cam2 {
|
||||
width: 25%;
|
||||
}
|
||||
#counters.cameras .cam label,
|
||||
#counters.cameras .cam2 label {
|
||||
line-height: 34px;
|
||||
font-size: 18px;
|
||||
}
|
||||
#counters.cameras .cam input,
|
||||
#counters.cameras .cam2 input {
|
||||
width: 90%;
|
||||
}
|
||||
#move_to,
|
||||
#move_to_2 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
#move_to .cam > div,
|
||||
#move_to .proj > div {
|
||||
#move_to_2 .cam > div,
|
||||
#move_to .cam2 > div,
|
||||
#move_to_2 .cam2 > div,
|
||||
#move_to .proj > div,
|
||||
#move_to_2 .proj > div,
|
||||
#move_to .proj2 > div,
|
||||
#move_to_2 .proj2 > div {
|
||||
width: 294px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#move_to .cam label,
|
||||
#move_to .proj label {
|
||||
#move_to_2 .cam label,
|
||||
#move_to .cam2 label,
|
||||
#move_to_2 .cam2 label,
|
||||
#move_to .proj label,
|
||||
#move_to_2 .proj label,
|
||||
#move_to .proj2 label,
|
||||
#move_to_2 .proj2 label {
|
||||
font-size: 18px;
|
||||
}
|
||||
#move_to .cam input,
|
||||
#move_to .proj input {
|
||||
#move_to_2 .cam input,
|
||||
#move_to .cam2 input,
|
||||
#move_to_2 .cam2 input,
|
||||
#move_to .proj input,
|
||||
#move_to_2 .proj input,
|
||||
#move_to .proj2 input,
|
||||
#move_to_2 .proj2 input {
|
||||
display: inline-block;
|
||||
width: 206px;
|
||||
}
|
||||
#move_to .cam button,
|
||||
#move_to .proj button {
|
||||
#move_to_2 .cam button,
|
||||
#move_to .cam2 button,
|
||||
#move_to_2 .cam2 button,
|
||||
#move_to .proj button,
|
||||
#move_to_2 .proj button,
|
||||
#move_to .proj2 button,
|
||||
#move_to_2 .proj2 button {
|
||||
padding: 7px 16px;
|
||||
float: right;
|
||||
}
|
||||
#move_to > .proj2,
|
||||
#move_to_2 > .proj2 {
|
||||
float: right;
|
||||
}
|
||||
.cam2,
|
||||
.proj2,
|
||||
.black {
|
||||
display: none;
|
||||
}
|
||||
.cam2 > *,
|
||||
.proj2 > *,
|
||||
.black > * {
|
||||
visibility: hidden;
|
||||
}
|
||||
.cam2.on,
|
||||
.proj2.on,
|
||||
.black.on {
|
||||
display: block;
|
||||
}
|
||||
.cam2.on > *,
|
||||
.proj2.on > *,
|
||||
.black.on > * {
|
||||
visibility: visible;
|
||||
}
|
||||
#overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
@ -829,6 +1241,21 @@ button:focus {
|
|||
color: #fff;
|
||||
text-shadow: 1px 1px 2px #000;
|
||||
}
|
||||
#spinnerCancel {
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 2000000000;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
text-align: center;
|
||||
margin-left: -40%;
|
||||
margin-top: 120px;
|
||||
width: 80%;
|
||||
}
|
||||
#spinnerCancel .btn {
|
||||
margin: 0 auto;
|
||||
background: rgba(80, 80, 80, 0.4);
|
||||
}
|
||||
.cp-app {
|
||||
position: relative !important;
|
||||
border-radius: 0px !important;
|
||||
|
|
|
@ -1,107 +1,201 @@
|
|||
{
|
||||
"version" : "2.0.0",
|
||||
"ext_port" : 1111,
|
||||
"profiles" : {
|
||||
"mcopy" : {
|
||||
"label" : "Default mcopy profile",
|
||||
"cam" : {
|
||||
"time" : 850,
|
||||
"delay" : 50,
|
||||
"momentary" : 0
|
||||
},
|
||||
"proj" : {
|
||||
"time" : 1400,
|
||||
"delay" : 50,
|
||||
"momentary" : 0
|
||||
},
|
||||
"black" : {
|
||||
"before" : 0,
|
||||
"after" : 0
|
||||
}
|
||||
},
|
||||
"jk103" : {
|
||||
"label" : "JK103",
|
||||
"cam" : {
|
||||
"time" : 600,
|
||||
"delay" : 50,
|
||||
"momentary" : 240
|
||||
},
|
||||
"proj" : {
|
||||
"time" : 950,
|
||||
"delay" : 50,
|
||||
"momentary" : 240
|
||||
},
|
||||
"black" : {
|
||||
"before" : 0,
|
||||
"after" : 0
|
||||
}
|
||||
},
|
||||
"jk_original" : {
|
||||
"label" : "JK45 profile",
|
||||
"cam" : {
|
||||
"time" : 750,
|
||||
"delay" : 50,
|
||||
"momentary" : 300
|
||||
},
|
||||
"proj" : {
|
||||
"time" : 1300,
|
||||
"delay" : 50,
|
||||
"momentary" : 300
|
||||
},
|
||||
"black" : {
|
||||
"before" : 250,
|
||||
"after" : 250
|
||||
}
|
||||
},
|
||||
"intval3" : {
|
||||
"label" : "INTVAL3",
|
||||
"cam" : {
|
||||
"time" : 630,
|
||||
"delay" : 50,
|
||||
"momentary" : 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"arduino" : {
|
||||
"baud" : 57600,
|
||||
"board" : "uno",
|
||||
"serialDelay" : 20,
|
||||
"sequenceDelay" : 100,
|
||||
"cam" : {
|
||||
"time" : 850,
|
||||
"delay" : 50,
|
||||
"momentary" : 300
|
||||
},
|
||||
"proj" : {
|
||||
"time" : 1300,
|
||||
"delay" : 50,
|
||||
"momentary" : 300
|
||||
},
|
||||
"black" : {
|
||||
"before" : 250,
|
||||
"after" : 250
|
||||
},
|
||||
"cmd" : {
|
||||
"debug" : "d",
|
||||
"connect": "i",
|
||||
"light" : "l",
|
||||
"camera" : "c",
|
||||
"projector" : "p",
|
||||
"black" : "b",
|
||||
"cam_forward" : "e",
|
||||
"cam_backward" : "f",
|
||||
"proj_forward" : "g",
|
||||
"proj_backward" : "h",
|
||||
"proj_identifier" : "j",
|
||||
"cam_identifier" : "k",
|
||||
"mcopy_identifier" : "m",
|
||||
"cam_timed" : "n",
|
||||
"proj_identifier" : "j",
|
||||
"cam_identifier" : "k",
|
||||
"light_identifier" : "o",
|
||||
"proj_light_identifier" : "q",
|
||||
"proj_cam_light_identifier" : "r",
|
||||
"proj_cam_identifier" : "s"
|
||||
}
|
||||
}
|
||||
}
|
||||
"version": "1.8.120",
|
||||
"ext_port": 1111,
|
||||
"profiles": {
|
||||
"mcopy": {
|
||||
"label": "Default mcopy profile",
|
||||
"cam": {
|
||||
"time": 850,
|
||||
"delay": 50,
|
||||
"momentary": 0
|
||||
},
|
||||
"proj": {
|
||||
"time": 1400,
|
||||
"delay": 50,
|
||||
"momentary": 0
|
||||
},
|
||||
"black": {
|
||||
"before": 100,
|
||||
"after": 100
|
||||
},
|
||||
"light": false
|
||||
},
|
||||
"jk103": {
|
||||
"label": "JK103",
|
||||
"cam": {
|
||||
"time": 600,
|
||||
"delay": 50,
|
||||
"momentary": 240
|
||||
},
|
||||
"proj": {
|
||||
"time": 950,
|
||||
"delay": 50,
|
||||
"momentary": 240
|
||||
},
|
||||
"black": {
|
||||
"before": 0,
|
||||
"after": 0
|
||||
},
|
||||
"light": false
|
||||
},
|
||||
"jk_original": {
|
||||
"label": "JK45 profile",
|
||||
"cam": {
|
||||
"time": 750,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"proj": {
|
||||
"time": 1300,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"black": {
|
||||
"before": 250,
|
||||
"after": 250
|
||||
},
|
||||
"light": false
|
||||
},
|
||||
"intval3": {
|
||||
"label": "INTVAL3",
|
||||
"cam": {
|
||||
"time": 630,
|
||||
"delay": 50,
|
||||
"momentary": 0
|
||||
},
|
||||
"light": false
|
||||
},
|
||||
"jk_mono": {
|
||||
"label": "MONO's JK",
|
||||
"cam": {
|
||||
"time": 750,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"proj": {
|
||||
"time": 1300,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"light": false,
|
||||
"projector_second": true
|
||||
},
|
||||
"oxberry": {
|
||||
"label": "Oxberry",
|
||||
"cam": {
|
||||
"time": 550,
|
||||
"delay": 50,
|
||||
"momentary": 130
|
||||
},
|
||||
"proj": {
|
||||
"time": 1340,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"light": false
|
||||
},
|
||||
"norris": {
|
||||
"label": "Norris",
|
||||
"cam": {
|
||||
"time": 650,
|
||||
"delay": 50,
|
||||
"momentary": 130
|
||||
},
|
||||
"light": false
|
||||
}
|
||||
},
|
||||
"cmd": {
|
||||
"camera_forward": "CF",
|
||||
"camera_backward": "CB",
|
||||
"projector_forward": "PF",
|
||||
"projector_backward": "PB",
|
||||
"black_forward": "BF",
|
||||
"black_backward": "BB",
|
||||
"camera_second_forward": "C2F",
|
||||
"camera_second_backward": "C2B",
|
||||
"cameras_forward": "CCF",
|
||||
"cameras_backward": "CCB",
|
||||
"camera_forward_camera_second_backward": "CFCB",
|
||||
"camera_backward_camera_second_forward": "CBCF",
|
||||
"projector_second_forward": "P2F",
|
||||
"projector_second_backward": "P2B",
|
||||
"projectors_forward": "PPF",
|
||||
"projectors_backward": "PPB",
|
||||
"projector_forward_projector_second_backward": "PFPB",
|
||||
"projector_backward_projector_second_forward": "PBPF",
|
||||
"pause": "PA",
|
||||
"alert": "AL"
|
||||
},
|
||||
"arduino": {
|
||||
"baud": 57600,
|
||||
"board": "uno",
|
||||
"serialDelay": 20,
|
||||
"sequenceDelay": 100,
|
||||
"cam": {
|
||||
"time": 850,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"proj": {
|
||||
"time": 1300,
|
||||
"delay": 50,
|
||||
"momentary": 300
|
||||
},
|
||||
"black": {
|
||||
"before": 250,
|
||||
"after": 250
|
||||
},
|
||||
"cmd": {
|
||||
"debug": "d",
|
||||
"connect": "i",
|
||||
"light": "l",
|
||||
"camera": "c",
|
||||
"projector": "p",
|
||||
"black": "b",
|
||||
"camera_forward": "e",
|
||||
"camera_backward": "f",
|
||||
"projector_forward": "g",
|
||||
"projector_backward": "h",
|
||||
"projector_identifier": "j",
|
||||
"camera_identifier": "k",
|
||||
"mcopy_identifier": "m",
|
||||
"camera_timed": "n",
|
||||
"light_identifier": "o",
|
||||
"projector_light_identifier": "q",
|
||||
"projector_camera_light_identifier": "r",
|
||||
"projector_camera_identifier": "s",
|
||||
"projector_second_identifier": "t",
|
||||
"projectors_identifier": "d",
|
||||
"projector_second_forward": "u",
|
||||
"projector_second_backward": "v",
|
||||
"projector_second": "w",
|
||||
"projectors": "x",
|
||||
"camera_second_identifier": "y",
|
||||
"cameras_identifier": "a",
|
||||
"camera_second_forward": "1",
|
||||
"camera_second_backward": "2",
|
||||
"camera_second": "3",
|
||||
"cameras": "4",
|
||||
"camera_projectors_identifier": "5",
|
||||
"cameras_projector_identifier": "6",
|
||||
"cameras_projectors_identifier": "7",
|
||||
"capper_identifier": "C",
|
||||
"camera_capper_identifier": "8",
|
||||
"camera_capper_projector_identifier": "9",
|
||||
"camera_capper_projectors_identifier": "0",
|
||||
"capper_on": "A",
|
||||
"capper_off": "B",
|
||||
"camera_open_forward": "J",
|
||||
"camera_open_backward": "K",
|
||||
"camera_close_forward": "L",
|
||||
"camera_close_backward": "M",
|
||||
"takeup_forward": "D",
|
||||
"takeup_backward": "F",
|
||||
"error": "E",
|
||||
"camera_exposure": "G",
|
||||
"state": "H",
|
||||
"home": "I",
|
||||
"offset": "O"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.4 MiB |
Binary file not shown.
After Width: | Height: | Size: 6.5 MiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
|
@ -0,0 +1,278 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>display</title>
|
||||
<style>
|
||||
body{
|
||||
background: #000;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
max-width: 100%;
|
||||
max-height: 100vh;
|
||||
}
|
||||
body.meter {
|
||||
background: rgb(117, 117, 117);
|
||||
}
|
||||
body.meter #img,
|
||||
body.meter #can {
|
||||
display: none;
|
||||
}
|
||||
body.image #can{
|
||||
display: none;
|
||||
}
|
||||
body.image #img {
|
||||
display: block;
|
||||
}
|
||||
#img {
|
||||
position: absolute;
|
||||
/*background-image: url(".../img/background.jpg");*/
|
||||
background-repeat:no-repeat;
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
}
|
||||
#can{
|
||||
margin: 0;
|
||||
background: #fff;
|
||||
display: none;
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
#can.show{
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="img">
|
||||
</div>
|
||||
<canvas id="can">
|
||||
</canvas>
|
||||
<script>
|
||||
'use strict';
|
||||
const { ipcRenderer } = require('electron')
|
||||
const remote = require('@electron/remote')
|
||||
let imgTmp;
|
||||
function delay (ms) {
|
||||
return new Promise((resolve) => {
|
||||
return setTimeout(resolve, ms)
|
||||
})
|
||||
}
|
||||
async function setImage (src) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
imgTmp = new Image()
|
||||
let img = document.getElementById('img')
|
||||
let body = document.querySelector('body')
|
||||
body.className = ''
|
||||
body.classList.add('image')
|
||||
imgTmp.onload = function () {
|
||||
img.style.backgroundImage = `url('${src}')`
|
||||
return resolve(src)
|
||||
}
|
||||
imgTmp.src = src
|
||||
})
|
||||
}
|
||||
|
||||
function setBlank () {
|
||||
let img = document.getElementById('img')
|
||||
img.style.background = ''
|
||||
img.style.backgroundUrl = ''
|
||||
img.style.backgroundColor = 'black'
|
||||
}
|
||||
async function onMeter () {
|
||||
console.log('meter')
|
||||
const body = document.querySelector('body')
|
||||
body.className = ''
|
||||
body.classList.add('meter')
|
||||
}
|
||||
async function onFocus () {
|
||||
console.log('focus')
|
||||
const can = document.getElementById('can')
|
||||
const dpr = window.devicePixelRatio || 1
|
||||
const body = document.querySelector('body')
|
||||
let ctx;
|
||||
body.className = ''
|
||||
if (!can.classList.contains('show')) {
|
||||
can.classList.add('show')
|
||||
}
|
||||
can.width = window.innerWidth * dpr
|
||||
can.height = window.innerHeight * dpr
|
||||
|
||||
can.style.width = `${window.innerWidth}px`
|
||||
can.style.height = `${window.innerHeight}px`
|
||||
|
||||
ctx = can.getContext('2d')
|
||||
ctx.scale(dpr, dpr)
|
||||
|
||||
try{
|
||||
await drawFocus(can, ctx)
|
||||
} catch (err) {
|
||||
alert(JSON.stringify(err))
|
||||
}
|
||||
}
|
||||
async function drawFocus (can, ctx) {
|
||||
const count = 20
|
||||
const half = Math.round(count / 2)
|
||||
const dpr = window.devicePixelRatio || 1
|
||||
const w = can.width / dpr
|
||||
const h = can.height / dpr
|
||||
const longest = w >= h ? w * 1.5 : h * 1.5
|
||||
const opp = Math.tan(360 / (count * 32)) * longest / 10
|
||||
|
||||
//console.log(`l: ${longest}`)
|
||||
//console.log(`${360 / (count * 8)}deg`)
|
||||
//console.log(`o: ${opp}`)
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(w / 2, h / 2)
|
||||
ctx.lineTo((w / 2) + opp, longest)
|
||||
ctx.lineTo((w / 2) - opp, longest)
|
||||
ctx.fill()
|
||||
ctx.translate(w / 2, h / 2);
|
||||
ctx.rotate((360 / count) * Math.PI / 180)
|
||||
ctx.translate(- w / 2, -h / 2)
|
||||
}
|
||||
}
|
||||
async function onField (evt, arg) {
|
||||
console.log('field guide')
|
||||
const can = document.getElementById('can')
|
||||
const dpr = window.devicePixelRatio || 1
|
||||
const screen = window.outerWidth / window.outerHeight
|
||||
const body = document.querySelector('body')
|
||||
let ctx
|
||||
body.className = ''
|
||||
if (!can.classList.contains('show')) {
|
||||
can.classList.add('show')
|
||||
}
|
||||
if (arg.ratio) {
|
||||
if (arg.ratio < screen) {
|
||||
can.width = (window.innerHeight * arg.ratio) * dpr
|
||||
can.height = window.innerHeight * dpr
|
||||
} else {
|
||||
can.width = window.innerWidth * dpr
|
||||
can.height = (window.innerWidth / arg.ratio) * dpr
|
||||
}
|
||||
} else {
|
||||
can.width = window.innerWidth * dpr
|
||||
can.height = window.innerHeight * dpr
|
||||
}
|
||||
|
||||
|
||||
if (arg.ratio) {
|
||||
if (arg.ratio < screen) {
|
||||
can.style.width = `${window.innerHeight * arg.ratio}px`
|
||||
can.style.height = `${window.innerHeight}px`
|
||||
} else {
|
||||
can.style.width = `${window.innerWidth}px`
|
||||
can.style.height = `${window.innerWidth / arg.ratio}px`
|
||||
}
|
||||
} else {
|
||||
can.style.width = `${window.innerWidth}px`
|
||||
can.style.height = `${window.innerHeight}px`
|
||||
}
|
||||
|
||||
ctx = can.getContext('2d')
|
||||
ctx.scale(dpr, dpr)
|
||||
|
||||
try{
|
||||
await drawField(can, ctx)
|
||||
} catch (err) {
|
||||
alert(JSON.stringify(err))
|
||||
}
|
||||
}
|
||||
// draw a field guide
|
||||
async function drawField (can, ctx) {
|
||||
const count = 20
|
||||
const half = Math.round(count / 2)
|
||||
const dpr = window.devicePixelRatio || 1
|
||||
const w = can.width / dpr
|
||||
const h = can.height / dpr
|
||||
const wsec = w / count
|
||||
const hsec = h / count
|
||||
const spacer = 12
|
||||
const fontSize = 18
|
||||
|
||||
ctx.lineWidth = 2
|
||||
|
||||
ctx.moveTo(w / 2, 0)
|
||||
ctx.lineTo(w / 2, h)
|
||||
ctx.stroke()
|
||||
ctx.moveTo(0, h / 2)
|
||||
ctx.lineTo(w, h / 2)
|
||||
ctx.stroke()
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
ctx.moveTo(wsec * i, hsec * i)
|
||||
ctx.lineTo(wsec * i, h - (hsec * i))
|
||||
ctx.stroke()
|
||||
ctx.moveTo(wsec * i, hsec * i)
|
||||
ctx.lineTo(w - (wsec * i), hsec * i)
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
ctx.lineWidth = 1
|
||||
|
||||
ctx.font = `${fontSize}px Arial`
|
||||
for (let i = 0; i < half; i++) {
|
||||
//left count
|
||||
ctx.fillText(`${(half - i)}`, (wsec * i) + spacer, (h / 2) - spacer)
|
||||
//right count
|
||||
ctx.fillText(`${(half - i)}`, (w - (wsec * i)) - (spacer * 2), (h / 2) + (spacer * 2))
|
||||
//up count
|
||||
ctx.fillText(`${(half - i)}`, (w / 2) + spacer, (hsec * i) + spacer + (fontSize / 2) )
|
||||
//down count
|
||||
ctx.fillText(`${(half - i)}`, (w / 2) - (spacer * 2), (h - (hsec * i)) - spacer)
|
||||
}
|
||||
}
|
||||
async function onDigital (event, arg) {
|
||||
if (arg.src) {
|
||||
if (arg.exposure) {
|
||||
setBlank()
|
||||
await delay(10)
|
||||
}
|
||||
try {
|
||||
await setImage(arg.src)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
if (arg.exposure) {
|
||||
await delay(arg.exposure)
|
||||
setBlank()
|
||||
}
|
||||
ipcRenderer.send('display_load', { src : arg.src })
|
||||
}
|
||||
return event.returnValue = true
|
||||
}
|
||||
|
||||
async function onEscape (evt) {
|
||||
let isEscape = false
|
||||
let win
|
||||
|
||||
evt = evt || window.event
|
||||
|
||||
if ('key' in evt) {
|
||||
isEscape = (evt.key == 'Escape' || evt.key == 'Esc')
|
||||
} else {
|
||||
isEscape = (evt.keyCode == 27)
|
||||
}
|
||||
|
||||
if (isEscape) {
|
||||
win = remote.getCurrentWindow()
|
||||
win.close()
|
||||
}
|
||||
}
|
||||
ipcRenderer.on('display', onDigital)
|
||||
ipcRenderer.on('field', onField)
|
||||
ipcRenderer.on('meter', onMeter)
|
||||
ipcRenderer.on('focus', onFocus)
|
||||
document.onkeydown = onEscape
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
<?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-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.debugger</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -18,17 +18,17 @@ var scripts = [
|
|||
'./src/index.js'
|
||||
];
|
||||
|
||||
gulp.task('js', function () {
|
||||
gulp.task('js', () => {
|
||||
'use strict';
|
||||
return gulp.src(scripts)
|
||||
.pipe(concat('app.js'))
|
||||
.pipe(gulp.dest('./js/'));
|
||||
});
|
||||
|
||||
gulp.task('less', function () {
|
||||
gulp.task('less', () => {
|
||||
return gulp.src('./less/app.less')
|
||||
.pipe(less())
|
||||
.pipe(gulp.dest('./css'));
|
||||
});
|
||||
|
||||
gulp.task('default', ['js', 'less']);
|
||||
gulp.task('default', gulp.parallel('js', 'less'));
|
||||
|
|
252
app/index.html
252
app/index.html
|
@ -13,42 +13,66 @@
|
|||
</head>
|
||||
<body onload="init();" style="background:#272b30;">
|
||||
<nav id="toolbar"></nav>
|
||||
<div id="screens">
|
||||
<div id="screens" class="hide">
|
||||
<div id="sequencer" class="screen" style="display: block;">
|
||||
<div id="counters">
|
||||
<div class="cam">
|
||||
<label>CAMERA</label>
|
||||
<input type="number" id="seq_cam_count" class="count" value="00000" onchange="gui.counterFormat(this, mcopy.state.camera.pos);" onblur="gui.updateCam(this);" />
|
||||
<input type="number" id="seq_cam_count" class="count" value="00000" onchange="gui.counterFormat(this, cam.pos);" onblur="gui.updateCam(this);" />
|
||||
</div>
|
||||
<div class="cam2">
|
||||
<label>CAMERA</label>
|
||||
<input type="number" id="seq_cam_2_count" class="count" value="00000" onchange="gui.counterFormat(this, cam.second.pos);" onblur="gui.updateCam2(this);" />
|
||||
</div>
|
||||
<div class="proj2">
|
||||
<label>PROJECTOR 2</label>
|
||||
<input type="number" id="seq_proj_2_count" class="count" value="00000" onchange="gui.counterFormat(this, proj.second.pos);" onblur="gui.updateProj2(this);" />
|
||||
</div>
|
||||
<div class="proj">
|
||||
<label>PROJECTOR</label>
|
||||
<input type="number" id="seq_proj_count" class="count" value="00000" onchange="gui.counterFormat(this, mcopy.state.projector.pos);" onblur="gui.updateProj(this);" />
|
||||
<input type="number" id="seq_proj_count" class="count" value="00000" onchange="gui.counterFormat(this, proj.pos);" onblur="gui.updateProj(this);" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="seq_scroll">
|
||||
<div id="sequence">
|
||||
<div id="cam_forward" class="row" y="0"></div>
|
||||
<div id="proj_forward" class="row" y="1"></div>
|
||||
<div id="cam_backward" class="row spacer" y="0"></div>
|
||||
<div id="proj_backward" class="row" y="1"></div>
|
||||
<div id="camera_forward" class="row" y="0"></div>
|
||||
<div id="camera_second_forward" class="row cam2" y="2"></div>
|
||||
<div id="projector_forward" class="row" y="1"></div>
|
||||
<div id="projector_second_forward" class="row proj2" y="3"></div>
|
||||
|
||||
<div id="camera_backward" class="row spacer" y="0"></div>
|
||||
<div id="camera_second_backward" class="row cam2" y="2"></div>
|
||||
<div id="projector_backward" class="row" y="1"></div>
|
||||
<div id="projector_second_backward" class="row proj2" y="3"></div>
|
||||
|
||||
<div id="black" class="row black"></div>
|
||||
|
||||
<div id="light_set" class="row spacer"></div>
|
||||
<div id="numbers" class="row"></div>
|
||||
</div>
|
||||
<div id="seq_labels">
|
||||
<div><span>CAM </span><i class="fa fa-plus"></i></div>
|
||||
<div><span>PRO </span><i class="fa fa-plus"></i></div>
|
||||
<div class="cam2"><span>CAM2 </span><i class="fa fa-plus"></i></div>
|
||||
<div><span>PROJ </span><i class="fa fa-plus"></i></div>
|
||||
<div class="proj2"><span>PROJ2 </span><i class="fa fa-plus"></i></div>
|
||||
|
||||
<div class="spacer"><span>CAM </span><i class="fa fa-minus"></i></div>
|
||||
<div><span>PRO </span><i class="fa fa-minus"></i></div>
|
||||
<div class="cam2"><span>CAM2 </span><i class="fa fa-minus"></i></div>
|
||||
<div><span>PROJ </span><i class="fa fa-minus"></i></div>
|
||||
<div class="proj2"><span>PROJ2 </span><i class="fa fa-minus"></i></div>
|
||||
|
||||
<div class="black"><span>BLANK </span><i class="fa fa-times"></i></div>
|
||||
|
||||
<div class="spacer"><span>LIGHT</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="actions">
|
||||
<button id="seq_run" onclick="seq.init();">RUN</button>
|
||||
<button id="seq_stop" onclick="seq.stop(true);">STOP</button>
|
||||
<button id="seq_clear" onclick="gui.grid.clear();">CLEAR</button>
|
||||
<button id="seq_plus24" onclick="gui.grid.plus_24();">+ 24</button>
|
||||
<button id="seq_run" onclick="seq.start();">START</button>
|
||||
<button id="seq_pause" onclick="seq.pause();">STOP</button>
|
||||
<button id="seq_stop" onclick="seq.stop();">STOP</button>
|
||||
<button id="seq_clear" onclick="grid.clear();">CLEAR</button>
|
||||
<button id="seq_plus24" onclick="grid.plus_24();">+ 24</button>
|
||||
<button id="seq_mscript" onclick="mse.mscript.fromSequence();">TO SCRIPT</button>
|
||||
<input id="seq_scroll_state" type="number" min="0" value="00000" />
|
||||
</div>
|
||||
|
@ -58,11 +82,17 @@
|
|||
<div class="cam_end">Camera end: <span>00000</span></div>
|
||||
<div class="proj_end">Projector end: <span>00000</span></div>
|
||||
</div>
|
||||
<div id="seq_loop">
|
||||
<div id="seq_loop_wrap">
|
||||
<h3>LOOPS</h3>
|
||||
<input type="number" min="1" id="seq_loop" value="00001" onchange="this.value = gui.fmtZero(this.value, 6); gui.grid.loopChange(this);"/>
|
||||
<input type="number" min="1" id="seq_loop" value="00001" onchange="this.value = gui.fmtZero(this.value, 6); seq.setLoops(parseInt(this.value));"/>
|
||||
<div id="loop_current"></div>
|
||||
</div>
|
||||
<div id="seq_progress">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
|
||||
<span class="sr-only">0% Complete</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="script" class="screen">
|
||||
<textarea id="editor"></textarea>
|
||||
|
@ -76,73 +106,87 @@
|
|||
</footer>
|
||||
</div>
|
||||
<div id="controls" class="screen">
|
||||
<div id="counters_2">
|
||||
<div id="counters_2" class="clearfix">
|
||||
<div class="cam">
|
||||
<label>CAMERA</label>
|
||||
<input type="number" id="seq_cam_count_2" class="count" value="00000" onchange="gui.counterFormat(this, mcopy.state.camera.pos);" onblur="gui.updateCam(this);" />
|
||||
<input type="number" id="seq_cam_count_2" class="count" value="00000" onchange="gui.counterFormat(this, cam.pos);" onblur="gui.updateCam(this);" />
|
||||
</div>
|
||||
<div class="proj">
|
||||
<label>PROJECTOR</label>
|
||||
<input type="number" id="seq_proj_count_2" class="count" value="00000" onchange="gui.counterFormat(this, mcopy.state.projector.pos);" onblur="gui.updateProj(this);" />
|
||||
<input type="number" id="seq_proj_count_2" class="count" value="00000" onchange="gui.counterFormat(this, proj.pos);" onblur="gui.updateProj(this);" />
|
||||
</div>
|
||||
</div>
|
||||
<div id="move_to">
|
||||
<div id="move_to" class="clearfix">
|
||||
<div class="cam">
|
||||
<!--<label>MOVE TO</label>-->
|
||||
<div>
|
||||
<input type="number" id="move_cam_to" class="count" value="00000" onchange="gui.counterFormat(this, this.value);" />
|
||||
<button id="move_cam_to_go" onclick="return cmd.cam_to();">GO TO</button>
|
||||
<button id="move_cam_to_go" onclick="return cmd.camera_to();">GO TO</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="proj">
|
||||
<!--<label>MOVE TO</label>-->
|
||||
<div>
|
||||
<input type="number" id="move_proj_to" class="count" value="00000" onchange="gui.counterFormat(this, this.value);"/>
|
||||
<button id="move_proj_to_go" onclick="return cmd.proj_to();">GO TO</button>
|
||||
<button id="move_proj_to_go" onclick="return cmd.projector_to();">GO TO</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="buttons" class="clearfix">
|
||||
<div>
|
||||
<div>
|
||||
<button id="cmd_cam_forward" onclick="cmd.cam_forward(light.color);" class="cmd fwd">
|
||||
<button id="cmd_cam_forward" onclick="cmd.camera_forward(light.color);" class="cmd fwd">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
CAMERA +1
|
||||
<i class="fa fa-step-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="cmd_cam_backward" onclick="cmd.cam_backward(light.color);" class="cmd bwd">
|
||||
<button id="cmd_cam_backward" onclick="cmd.camera_backward(light.color);" class="cmd bwd">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
CAMERA -1
|
||||
<i class="fa fa-step-backward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<div class="hide">
|
||||
<button id="cmd_black_forward" onclick="cmd.black_forward();" class="cmd fwd">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
BLANK +1
|
||||
<i class="fa fa-step-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<div class="hide">
|
||||
<button id="cmd_black_backward" onclick="cmd.black_backward();" class="cmd bwd">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
BLANK -1
|
||||
<i class="fa fa-step-backward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="hide">
|
||||
<button id="cmd_capper_on" onclick="cmd.capper_on();" class="cmd capper">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
CAPPER ON
|
||||
<i class="fa fa-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="hide">
|
||||
<button id="cmd_capper_off" onclick="cmd.capper_off();" class="cmd capper active">
|
||||
<i class="fa fa-eye"></i>
|
||||
CAPPER OFF
|
||||
<i class="fa fa-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<button id="cmd_proj_forward" onclick="cmd.proj_forward();" class="cmd fwd">
|
||||
<button id="cmd_proj_forward" onclick="cmd.projector_forward();" class="cmd fwd">
|
||||
<i class="fa fa-film"></i>
|
||||
PROJECTOR +1
|
||||
<i class="fa fa-step-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="cmd_proj_backward" onclick="cmd.proj_backward();" class="cmd bwd">
|
||||
<button id="cmd_proj_backward" onclick="cmd.projector_backward();" class="cmd bwd">
|
||||
<i class="fa fa-film"></i>
|
||||
PROJECTOR -1
|
||||
<i class="fa fa-step-backward"></i>
|
||||
|
@ -150,9 +194,80 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div id="log"></div>
|
||||
</footer>
|
||||
<div id="counters_3" class="clearfix">
|
||||
<div class="cam2">
|
||||
<label>CAMERA 2</label>
|
||||
<input type="number" id="seq_cam_2_count_2" class="count" value="00000" onchange="gui.counterFormat(this, cam.second.pos);" onblur="gui.updateCam2(this);" />
|
||||
</div>
|
||||
<div class="proj2">
|
||||
<label>PROJECTOR 2</label>
|
||||
<input type="number" id="seq_proj_2_count_2" class="count" value="00000" onchange="gui.counterFormat(this, proj.second.pos);" onblur="gui.updateProj2(this);" />
|
||||
</div>
|
||||
</div>
|
||||
<div id="move_to_2" class="clearfix">
|
||||
<div class="cam2">
|
||||
<!--<label>MOVE TO</label>-->
|
||||
<div>
|
||||
<input type="number" id="move_cam_to_2" class="count" value="00000" onchange="gui.counterFormat(this, this.value);" />
|
||||
<button id="move_cam_to_go_2" onclick="return cmd.camera_second_to();">GO TO</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="proj2">
|
||||
<!--<label>MOVE TO</label>-->
|
||||
<div>
|
||||
<input type="number" id="move_proj_to_2" class="count" value="00000" onchange="gui.counterFormat(this, this.value);"/>
|
||||
<button id="move_proj_to_go_2" onclick="return cmd.projector_second_to();">GO TO</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="buttons_2" class="clearfix">
|
||||
<div class="cam2">
|
||||
<div>
|
||||
<button id="cmd_cam2_forward" onclick="cmd.camera_second_forward(light.color);" class="cmd fwd">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
CAMERA 2 +1
|
||||
<i class="fa fa-step-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="cmd_cam2_backward" onclick="cmd.camera_second_backward(light.color);" class="cmd bwd">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
CAMERA 2 -1
|
||||
<i class="fa fa-step-backward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="cmd_black2_forward" onclick="cmd.black2_forward();" class="cmd fwd">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
BLANK +1
|
||||
<i class="fa fa-step-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="cmd_black2_backward" onclick="cmd.black2_backward();" class="cmd bwd">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
BLANK -1
|
||||
<i class="fa fa-step-backward"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="proj2">
|
||||
<div>
|
||||
<button id="cmd_proj2_forward" onclick="cmd.projector_second_forward();" class="cmd fwd">
|
||||
<i class="fa fa-film"></i>
|
||||
PROJECTOR 2 +1
|
||||
<i class="fa fa-step-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button id="cmd_proj2_backward" onclick="cmd.projector_second_backward();" class="cmd bwd">
|
||||
<i class="fa fa-film"></i>
|
||||
PROJECTOR 2 -1
|
||||
<i class="fa fa-step-backward"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="light" class="screen">
|
||||
<div id="colors-tabs"></div>
|
||||
|
@ -245,8 +360,54 @@
|
|||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<div id="settings" class="screen">
|
||||
<div id="video" class="screen">
|
||||
<div>
|
||||
<div>
|
||||
<div id="path_bar">
|
||||
<input id="filmout_file" type="text" onclick="filmout.selectFile();" readonly />
|
||||
<button onclick="$('#projector_type_digital').click();">USE FILE</button>
|
||||
<select id="filmout_displays"></select>
|
||||
</div>
|
||||
|
||||
<div id="filmout_preview_wrap">
|
||||
<div id="filmout_monitor">
|
||||
<div id="filmout"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="filmout_stats">
|
||||
<div id="filmout_stats_video">
|
||||
<h3>File</h3>
|
||||
<div id="filmout_stats_video_name"></div>
|
||||
<div id="filmout_stats_video_size"></div>
|
||||
<div id="filmout_stats_video_frames"></div>
|
||||
</div>
|
||||
<div id="filmout_stats_monitor">
|
||||
<h3>Monitor</h3>
|
||||
<div id="filmout_stats_monitor_size"></div>
|
||||
<div id="filmout_stats_monitor_aspect"></div>
|
||||
<div id="filmout_stats_monitor_scale"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="filmout_position_wrap">
|
||||
<div>
|
||||
<button id="filmout_rewind" title="Rewind 1 Frame" onclick="filmout.rewind();"><</button>
|
||||
<input id="filmout_position" class="count" type="number" value="00000" onchange="gui.counterFormat(this, this.value);" />
|
||||
<button id="filmout_advance" title="Advance 1 Frame" onclick="filmout.advance();">></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="filmout_functions">
|
||||
<div>
|
||||
<button id="filmout_preview" onclick="filmout.preview();">PREVIEW</button>
|
||||
<button id="filmout_meter" onclick="filmout.meter();">METER</button>
|
||||
<button id="filmout_focus" onclick="filmout.focus();">FOCUS</button>
|
||||
<button id="filmout_field" onclick="filmout.field();">FIELD GUIDE</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="settings" class="screen">
|
||||
<div class="left">
|
||||
<div>
|
||||
<h4>Devices</h4>
|
||||
<select id="devices">
|
||||
|
@ -259,6 +420,11 @@
|
|||
<select id="projector_device">
|
||||
<option>Not Set</option>
|
||||
</select>
|
||||
<input type="radio" id="projector_type_arduino" name="projector_type" value="arduino" checked="checked" />
|
||||
</div>
|
||||
<div class="spacer">
|
||||
<input type="text" id="digital" name="digital" placeholder="Digital file" onclick="filmout.selectFile();" data-file="" readonly />
|
||||
<input type="radio" id="projector_type_digital" name="projector_type" value="video" onclick="filmout.useFile();" />
|
||||
</div>
|
||||
<div>
|
||||
<h4>Camera</h4>
|
||||
|
@ -271,6 +437,13 @@
|
|||
<input type="text" id="intval" name="intval" placeholder="INTVAL3 URL"/>
|
||||
<input type="radio" id="camera_type_intval" name="camera_type" value="intval" onclick="devices.intval();" />
|
||||
</div>
|
||||
<div class="spacer">
|
||||
<input type="text" id="processing" name="processing" placeholder="PROCESSING URL" />
|
||||
<input type="radio" id="camera_type_processing" name="camera_type" value="processing" onclick="devices.processing();" />
|
||||
</div>
|
||||
<div>
|
||||
<div id="version"></div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Light</h4>
|
||||
<select id="light_device">
|
||||
|
@ -284,15 +457,32 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="spacer"></div>
|
||||
<div class="proj_time">
|
||||
<h4>Projector Time (ms)</h4>
|
||||
<input type="number" readonly id="proj_time" value="0" />
|
||||
<button id="submit_proj_time" class="hide">✓</button>
|
||||
</div>
|
||||
<div class="cam_time">
|
||||
<h4>Camera Time (ms)</h4>
|
||||
<input type="number" readonly id="cam_time" value="0" />
|
||||
<button id="submit_cam_time" class="hide" onclick="cam.exposure($('#cam_time').val());">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="overlay" onclick="gui.overlay(false);gui.spinner(false);"></div>
|
||||
<div id="spinner">
|
||||
<div id="spinnerMsg"></div>
|
||||
<div id="spinnerCancel">
|
||||
<div class="btn" style="margin:auto;" onclick="seq.cancel();">Cancel</div>
|
||||
</div>
|
||||
<div id="spinnerProgress" class="progress">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
|
||||
<span class="sr-only">0% Complete</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script src="./js/app.js"></script>
|
||||
|
|
|
@ -2472,79 +2472,65 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
},k.push(["lab",J])}).call(this);
|
||||
//fgnass.github.com/spin.js#v2.0.1
|
||||
!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define(b):a.Spinner=b()}(this,function(){"use strict";function a(a,b){var c,d=document.createElement(a||"div");for(c in b)d[c]=b[c];return d}function b(a){for(var b=1,c=arguments.length;c>b;b++)a.appendChild(arguments[b]);return a}function c(a,b,c,d){var e=["opacity",b,~~(100*a),c,d].join("-"),f=.01+c/d*100,g=Math.max(1-(1-a)/b*(100-f),a),h=j.substring(0,j.indexOf("Animation")).toLowerCase(),i=h&&"-"+h+"-"||"";return l[e]||(m.insertRule("@"+i+"keyframes "+e+"{0%{opacity:"+g+"}"+f+"%{opacity:"+a+"}"+(f+.01)+"%{opacity:1}"+(f+b)%100+"%{opacity:"+a+"}100%{opacity:"+g+"}}",m.cssRules.length),l[e]=1),e}function d(a,b){var c,d,e=a.style;for(b=b.charAt(0).toUpperCase()+b.slice(1),d=0;d<k.length;d++)if(c=k[d]+b,void 0!==e[c])return c;return void 0!==e[b]?b:void 0}function e(a,b){for(var c in b)a.style[d(a,c)||c]=b[c];return a}function f(a){for(var b=1;b<arguments.length;b++){var c=arguments[b];for(var d in c)void 0===a[d]&&(a[d]=c[d])}return a}function g(a,b){return"string"==typeof a?a:a[b%a.length]}function h(a){this.opts=f(a||{},h.defaults,n)}function i(){function c(b,c){return a("<"+b+' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">',c)}m.addRule(".spin-vml","behavior:url(#default#VML)"),h.prototype.lines=function(a,d){function f(){return e(c("group",{coordsize:k+" "+k,coordorigin:-j+" "+-j}),{width:k,height:k})}function h(a,h,i){b(m,b(e(f(),{rotation:360/d.lines*a+"deg",left:~~h}),b(e(c("roundrect",{arcsize:d.corners}),{width:j,height:d.width,left:d.radius,top:-d.width>>1,filter:i}),c("fill",{color:g(d.color,a),opacity:d.opacity}),c("stroke",{opacity:0}))))}var i,j=d.length+d.width,k=2*j,l=2*-(d.width+d.length)+"px",m=e(f(),{position:"absolute",top:l,left:l});if(d.shadow)for(i=1;i<=d.lines;i++)h(i,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(i=1;i<=d.lines;i++)h(i);return b(a,m)},h.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d<e.childNodes.length&&(e=e.childNodes[b+d],e=e&&e.firstChild,e=e&&e.firstChild,e&&(e.opacity=c))}}var j,k=["webkit","Moz","ms","O"],l={},m=function(){var c=a("style",{type:"text/css"});return b(document.getElementsByTagName("head")[0],c),c.sheet||c.styleSheet}(),n={lines:12,length:7,width:5,radius:10,rotate:0,corners:1,color:"#000",direction:1,speed:1,trail:100,opacity:.25,fps:20,zIndex:2e9,className:"spinner",top:"50%",left:"50%",position:"absolute"};h.defaults={},f(h.prototype,{spin:function(b){this.stop();{var c=this,d=c.opts,f=c.el=e(a(0,{className:d.className}),{position:d.position,width:0,zIndex:d.zIndex});d.radius+d.length+d.width}if(e(f,{left:d.left,top:d.top}),b&&b.insertBefore(f,b.firstChild||null),f.setAttribute("role","progressbar"),c.lines(f,c.opts),!j){var g,h=0,i=(d.lines-1)*(1-d.direction)/2,k=d.fps,l=k/d.speed,m=(1-d.opacity)/(l*d.trail/100),n=l/d.lines;!function o(){h++;for(var a=0;a<d.lines;a++)g=Math.max(1-(h+(d.lines-a)*n)%l*m,d.opacity),c.opacity(f,a*d.direction+i,g,d);c.timeout=c.el&&setTimeout(o,~~(1e3/k))}()}return c},stop:function(){var a=this.el;return a&&(clearTimeout(this.timeout),a.parentNode&&a.parentNode.removeChild(a),this.el=void 0),this},lines:function(d,f){function h(b,c){return e(a(),{position:"absolute",width:f.length+f.width+"px",height:f.width+"px",background:b,boxShadow:c,transformOrigin:"left",transform:"rotate("+~~(360/f.lines*k+f.rotate)+"deg) translate("+f.radius+"px,0)",borderRadius:(f.corners*f.width>>1)+"px"})}for(var i,k=0,l=(f.lines-1)*(1-f.direction)/2;k<f.lines;k++)i=e(a(),{position:"absolute",top:1+~(f.width/2)+"px",transform:f.hwaccel?"translate3d(0,0,0)":"",opacity:f.opacity,animation:j&&c(f.opacity,f.trail,l+k*f.direction,f.lines)+" "+1/f.speed+"s linear infinite"}),f.shadow&&b(i,e(h("#000","0 0 4px #000"),{top:"2px"})),b(d,b(i,h(g(f.color,k),"0 0 1px rgba(0,0,0,.1)")));return d},opacity:function(a,b,c){b<a.childNodes.length&&(a.childNodes[b].style.opacity=c)}});var o=e(a("group"),{behavior:"url(#default#VML)"});return!d(o,"transform")&&o.adj?i():j=d(o,"animation"),h});
|
||||
|
||||
const mcopy = {};
|
||||
mcopy.cfg = require('./data/cfg.json');
|
||||
|
||||
|
||||
const { remote, ipcRenderer } = require('electron');
|
||||
const dialog = require('electron').remote.dialog;
|
||||
const remote = require('@electron/remote');
|
||||
const { ipcRenderer } = require('electron');
|
||||
const { dialog } = remote;
|
||||
const notifier = require('node-notifier');
|
||||
const fs = require('fs');
|
||||
const uuid = require('uuid');
|
||||
const uuid = require('uuid').v4;
|
||||
const moment = require('moment');
|
||||
const path = require('path');
|
||||
const humanizeDuration = require('humanize-duration');
|
||||
const PACKAGE = require('./package.json');
|
||||
const cfg = require('./data/cfg.json');
|
||||
const gui = require('./lib/ui');
|
||||
const grid = require('./lib/ui/grid.js');
|
||||
const light = require('./lib/ui/light.js');
|
||||
const proj = require('./lib/ui/proj.js');
|
||||
const cam = require('./lib/ui/cam.js');
|
||||
const nav = require('./lib/ui/nav.js');
|
||||
const seq = require('./lib/ui/seq.js');
|
||||
const cmd = require('./lib/ui/cmd.js');
|
||||
const log = require('./lib/ui/log.js');
|
||||
const devices = require('./lib/ui/devices.js');
|
||||
const filmout = require('./lib/ui/filmout.js');
|
||||
const mse = require('./lib/ui/mscript.js');
|
||||
const mscript = require('./lib/mscript');
|
||||
|
||||
|
||||
const capper = require('./lib/ui/capper.js');
|
||||
const timing = require('./lib/ui/timing.js');
|
||||
const Mscript = require('./lib/mscript');
|
||||
const { delay } = require('./lib/delay');
|
||||
const alertObj = require('./lib/ui/alert.js');
|
||||
const { Log } = require('./lib/log');
|
||||
|
||||
let log;
|
||||
|
||||
/******
|
||||
State shared by ALL interfaces
|
||||
*******/
|
||||
mcopy.state = {
|
||||
version : '2.0.0', //use for file compatibility check
|
||||
camera : {
|
||||
pos : 0,
|
||||
direction: true
|
||||
},
|
||||
projector : {
|
||||
pos : 0,
|
||||
direction: true
|
||||
},
|
||||
sequence : {
|
||||
size : 24,
|
||||
arr : ['CF', 'PF'],
|
||||
light : ['255,255,255', ''],
|
||||
cmd : {
|
||||
camera: mcopy.cfg.arduino.cmd.camera,
|
||||
projector: mcopy.cfg.arduino.cmd.projector,
|
||||
cam_direction: mcopy.cfg.arduino.cmd.cam_direction,
|
||||
cam_direction: mcopy.cfg.arduino.cmd.proj_direction
|
||||
},
|
||||
pads: {
|
||||
cam_forward: 'CF',
|
||||
proj_forward : 'PF',
|
||||
black_forward : 'BF',
|
||||
|
||||
cam_backward: 'CB',
|
||||
proj_backward : 'PB',
|
||||
black_backward : 'BB',
|
||||
|
||||
light_set : 'L'
|
||||
}
|
||||
}
|
||||
version : PACKAGE.version //use for file compatibility check
|
||||
};
|
||||
//
|
||||
|
||||
function init () {
|
||||
async function init () {
|
||||
'use strict';
|
||||
|
||||
log = await Log({ label : 'ui' })
|
||||
|
||||
nav.init();
|
||||
gui.grid.init();
|
||||
gui.init();
|
||||
grid.init();
|
||||
mse.mscript.init();
|
||||
mse.console.init();
|
||||
log.init();
|
||||
|
||||
devices.init();
|
||||
filmout.init();
|
||||
light.init();
|
||||
proj.init();
|
||||
cam.init();
|
||||
seq.init();
|
||||
capper.init();
|
||||
alertObj.init();
|
||||
timing.init();
|
||||
};
|
|
@ -8,11 +8,13 @@
|
|||
@import "./scroll.less";
|
||||
@import "./settings.less";
|
||||
@import "./mscript.less";
|
||||
@import "./filmout.less";
|
||||
|
||||
#log{
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: @FOOTER_H;
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#screens{
|
||||
|
@ -77,9 +79,13 @@
|
|||
|
||||
#counters,
|
||||
#counters_2,
|
||||
#move_to{
|
||||
#counters_3,
|
||||
#move_to,
|
||||
#move_to_2{
|
||||
.cam,
|
||||
.proj{
|
||||
.cam2,
|
||||
.proj,
|
||||
.proj2{
|
||||
width: 50%;
|
||||
padding-bottom: 10px;
|
||||
label{
|
||||
|
@ -101,18 +107,52 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.cam{
|
||||
.cam,
|
||||
.cam2{
|
||||
float: left;
|
||||
}
|
||||
.proj{
|
||||
.proj,
|
||||
.proj2{
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
#move_to{
|
||||
#counters{
|
||||
&.projectors{
|
||||
.proj,
|
||||
.proj2{
|
||||
width: 25%;
|
||||
label{
|
||||
line-height: 34px;
|
||||
font-size: 18px;
|
||||
}
|
||||
input{
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.cameras{
|
||||
.cam,
|
||||
.cam2{
|
||||
width: 25%;
|
||||
label{
|
||||
line-height: 34px;
|
||||
font-size: 18px;
|
||||
}
|
||||
input{
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#move_to,
|
||||
#move_to_2{
|
||||
margin-top: 20px;
|
||||
.cam,
|
||||
.proj{
|
||||
.cam2,
|
||||
.proj,
|
||||
.proj2{
|
||||
> div {
|
||||
width: 294px;
|
||||
margin: 0 auto;
|
||||
|
@ -129,6 +169,25 @@
|
|||
float: right;
|
||||
}
|
||||
}
|
||||
> .proj2{
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.cam2,
|
||||
.proj2,
|
||||
.black{
|
||||
display : none;
|
||||
> * {
|
||||
visibility: hidden;
|
||||
}
|
||||
&.on {
|
||||
display: block;
|
||||
> * {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#overlay{
|
||||
|
@ -158,6 +217,22 @@
|
|||
text-shadow: 1px 1px 2px #000;
|
||||
}
|
||||
|
||||
#spinnerCancel{
|
||||
display:none;
|
||||
position: absolute;
|
||||
z-index: 2000000000;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
text-align: center;
|
||||
margin-left: -40%;
|
||||
margin-top: 120px;
|
||||
width: 80%;
|
||||
.btn{
|
||||
margin: 0 auto;
|
||||
background: rgba(80,80,80, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.cp-app{
|
||||
position: relative !important;
|
||||
border-radius: 0px !important;
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
#buttons{
|
||||
#buttons,
|
||||
#buttons_2{
|
||||
> div{
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
.proj2 {
|
||||
float: right !important;
|
||||
}
|
||||
}
|
||||
|
||||
.cmd{
|
||||
|
@ -38,6 +42,10 @@
|
|||
background: @BACKWARD;
|
||||
border-color: @BACKWARD;
|
||||
}
|
||||
&.capper{
|
||||
background: white;
|
||||
color: @BG;
|
||||
}
|
||||
i{
|
||||
color: @BG;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
#video{
|
||||
input,select{
|
||||
.button();
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
font-size: 21px;
|
||||
min-width: 300px;
|
||||
&.active{
|
||||
border-color: @SELECTED;
|
||||
color: @SELECTED;
|
||||
}
|
||||
}
|
||||
button, select {
|
||||
padding: 9px 16px 8px;
|
||||
}
|
||||
}
|
||||
|
||||
#path_bar{
|
||||
padding: 5px;
|
||||
height: 50px;
|
||||
input{
|
||||
float: left;
|
||||
}
|
||||
button{
|
||||
float: left;
|
||||
margin-left: 5px;
|
||||
}
|
||||
select{
|
||||
line-height: 41px;
|
||||
height: 37px;
|
||||
margin-right: 5px;
|
||||
float: right;
|
||||
box-sizing: content-box;
|
||||
padding: 0 0 0 8px;
|
||||
}
|
||||
}
|
||||
#filmout_file {
|
||||
|
||||
}
|
||||
#filmout_monitor{
|
||||
display: none;
|
||||
border: 2px solid white;
|
||||
box-sizing: border-box;
|
||||
height: 360px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
&.on{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
#filmout_preview_wrap {
|
||||
background: #000;
|
||||
width: 100%;
|
||||
height: 360px;
|
||||
}
|
||||
#filmout {
|
||||
position: absolute;
|
||||
background-repeat:no-repeat;
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: block;
|
||||
opacity: 0;
|
||||
&.on {
|
||||
opacity: 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
#filmout_position_wrap{
|
||||
padding-top: 5px;
|
||||
height: 50px;
|
||||
input{
|
||||
margin-right: 5px;
|
||||
margin-left: 5px;
|
||||
width: 308px !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
button, input{
|
||||
float: left;
|
||||
}
|
||||
> div{
|
||||
width: 425px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
#filmout_functions{
|
||||
padding-top: 5px;
|
||||
> div{
|
||||
width: 425px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
#filmout_stats_video,
|
||||
#filmout_stats_monitor{
|
||||
width: 150px;
|
||||
position: absolute;
|
||||
//background: grey;
|
||||
padding: 10px 5px;
|
||||
text-align: center;
|
||||
h3{
|
||||
font-size: 20px;
|
||||
margin: 16px 0 3px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
#filmout_stats_video{
|
||||
left: 5px;
|
||||
}
|
||||
#filmout_stats_monitor{
|
||||
right: 5px;
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
float: right;
|
||||
width: 90px;
|
||||
margin-right: 60px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
#seq_stats{
|
||||
|
@ -45,7 +46,7 @@
|
|||
.timing{
|
||||
}
|
||||
}
|
||||
#seq_loop{
|
||||
#seq_loop_wrap{
|
||||
width: 40%;
|
||||
float: left;
|
||||
padding: 0 0 0 56px;
|
||||
|
@ -64,43 +65,75 @@
|
|||
}
|
||||
}
|
||||
|
||||
#sequencer{
|
||||
|
||||
}
|
||||
#sequence{
|
||||
width: 970px;
|
||||
padding-bottom: 21px;
|
||||
padding-left: 70px;
|
||||
#cam_forward,
|
||||
#proj_forward,
|
||||
padding-left: 92px;
|
||||
#camera_forward,
|
||||
#camera_second_forward,
|
||||
#projector_forward,
|
||||
#projector_second_forward,
|
||||
#black_forward{
|
||||
clear: both;
|
||||
input[type=checkbox]{
|
||||
border: 2px solid @FORWARD;
|
||||
&:checked{
|
||||
background: @FORWARD;
|
||||
//background: radial-gradient(circle at 25px 25px, #00C4A0, #343434);
|
||||
}
|
||||
}
|
||||
>div{
|
||||
color: @FORWARD;
|
||||
}
|
||||
}
|
||||
#cam_backward,
|
||||
#proj_backward,
|
||||
#camera_backward,
|
||||
#camera_second_backward,
|
||||
#projector_backward,
|
||||
#projector_second_backward,
|
||||
#black_backward{
|
||||
clear: both;
|
||||
input[type=checkbox]{
|
||||
border: 2px solid @BACKWARD;
|
||||
&:checked{
|
||||
background: @BACKWARD;
|
||||
//background: radial-gradient(circle at 25px 25px, #AB1A25, #343434);
|
||||
}
|
||||
}
|
||||
>div{
|
||||
color: @BACKWARD;
|
||||
}
|
||||
}
|
||||
|
||||
#camera_second_forward,
|
||||
#projector_second_forward {
|
||||
input[type=checkbox]{
|
||||
border: 2px solid @FORWARD + @SECOND;
|
||||
&:checked{
|
||||
background: @FORWARD + @SECOND;
|
||||
}
|
||||
}
|
||||
>div{
|
||||
color: @FORWARD + @SECOND;
|
||||
}
|
||||
|
||||
}
|
||||
#camera_second_backward,
|
||||
#projector_second_backward{
|
||||
input[type=checkbox]{
|
||||
border: 2px solid @BACKWARD + @SECOND;
|
||||
&:checked{
|
||||
background: @BACKWARD + @SECOND;
|
||||
}
|
||||
}
|
||||
>div{
|
||||
color: @BACKWARD + @SECOND;
|
||||
}
|
||||
}
|
||||
#black{
|
||||
input[type=checkbox]{
|
||||
&:checked{
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
input[type=checkbox]{
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
|
@ -116,6 +149,10 @@
|
|||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
&.disabled{
|
||||
cursor: not-allowed;
|
||||
border-color: rgb(100, 100, 100);
|
||||
}
|
||||
}
|
||||
.L{
|
||||
display: inline-block;
|
||||
|
@ -164,10 +201,10 @@
|
|||
.monospace();
|
||||
background-color: #272b30;
|
||||
position: absolute;
|
||||
top: 115px;
|
||||
top: 113px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 15px;
|
||||
width: 54px;
|
||||
width: 75px;
|
||||
div{
|
||||
height: 43px;
|
||||
line-height: 35px;
|
||||
|
@ -177,11 +214,33 @@
|
|||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
i.fa{
|
||||
right: 3px;
|
||||
position: absolute;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
#loop_current{
|
||||
margin-top: 54px;
|
||||
width: 121px;
|
||||
font-family: 'Menlo', monospace;
|
||||
font-size: 22px;
|
||||
margin-top: 13px;
|
||||
margin-right: 50px;
|
||||
width: 93px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
float: right;
|
||||
color: @SELECTED;
|
||||
}
|
||||
}
|
||||
|
||||
#seq_pause{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#seq_progress{
|
||||
width: 100%;
|
||||
height: 15px;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
|
|
@ -1,25 +1,61 @@
|
|||
#settings{
|
||||
h4{
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
> div{
|
||||
width: 300px;
|
||||
margin: 0 auto;
|
||||
&.left{
|
||||
float: left;
|
||||
padding-left: 30px;
|
||||
}
|
||||
&.right{
|
||||
float: right;
|
||||
padding-right: 30px;
|
||||
input[type=number] {
|
||||
min-width: 200px;
|
||||
width: 200px;
|
||||
}
|
||||
input[readonly]{
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.spacer{
|
||||
height: 62px;
|
||||
}
|
||||
.proj_time{
|
||||
height: 111px;
|
||||
}
|
||||
.cam_time{
|
||||
height: 111px;
|
||||
}
|
||||
& > div {
|
||||
width: 270px;
|
||||
}
|
||||
}
|
||||
}
|
||||
> div > div{
|
||||
width: 360px;
|
||||
}
|
||||
input[type=text], select{
|
||||
input[type=text],
|
||||
input[type=number],
|
||||
select{
|
||||
.button();
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
font-size: 21px;
|
||||
min-width: 300px;
|
||||
max-width: 300px;
|
||||
&.active{
|
||||
border-color: @SELECTED;
|
||||
color: @SELECTED;
|
||||
}
|
||||
}
|
||||
input[type=text]{
|
||||
width: 200px;
|
||||
}
|
||||
button{
|
||||
margin-top: -1px;
|
||||
float: right;
|
||||
margin-top: 0px;
|
||||
float: right;
|
||||
padding: 8px 16px 9px;
|
||||
}
|
||||
input[type=radio]{
|
||||
float: right;
|
||||
|
@ -28,4 +64,15 @@
|
|||
.spacer{
|
||||
margin-top: 10px;
|
||||
}
|
||||
#version{
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
bottom: 10px;
|
||||
z-index: 1000;
|
||||
height: 14px;
|
||||
width: auto;
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
@FORWARD: #00C4A0;
|
||||
@BACKWARD: #AB1A25;
|
||||
@SELECTED: #DAE035;
|
||||
@SECOND : rgb(20, 20, 20);
|
||||
|
||||
@SEQ: #3C3636;
|
||||
@SCRIPT: rgb(39, 40, 34);
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<a name="module_lib/alert"></a>
|
||||
|
||||
## lib/alert
|
||||
|
||||
* [lib/alert](#module_lib/alert)
|
||||
* [~Alert](#module_lib/alert..Alert)
|
||||
* [.init()](#module_lib/alert..Alert+init)
|
||||
* [.listen()](#module_lib/alert..Alert+listen)
|
||||
* [.listener()](#module_lib/alert..Alert+listener)
|
||||
* [.start()](#module_lib/alert..Alert+start)
|
||||
|
||||
<a name="module_lib/alert..Alert"></a>
|
||||
|
||||
### lib/alert~Alert
|
||||
Class for pushing an alert to the UI from the backend.
|
||||
|
||||
**Kind**: inner class of [<code>lib/alert</code>](#module_lib/alert)
|
||||
|
||||
* [~Alert](#module_lib/alert..Alert)
|
||||
* [.init()](#module_lib/alert..Alert+init)
|
||||
* [.listen()](#module_lib/alert..Alert+listen)
|
||||
* [.listener()](#module_lib/alert..Alert+listener)
|
||||
* [.start()](#module_lib/alert..Alert+start)
|
||||
|
||||
<a name="module_lib/alert..Alert+init"></a>
|
||||
|
||||
#### alert.init()
|
||||
**Kind**: instance method of [<code>Alert</code>](#module_lib/alert..Alert)
|
||||
<a name="module_lib/alert..Alert+listen"></a>
|
||||
|
||||
#### alert.listen()
|
||||
**Kind**: instance method of [<code>Alert</code>](#module_lib/alert..Alert)
|
||||
<a name="module_lib/alert..Alert+listener"></a>
|
||||
|
||||
#### alert.listener()
|
||||
**Kind**: instance method of [<code>Alert</code>](#module_lib/alert..Alert)
|
||||
<a name="module_lib/alert..Alert+start"></a>
|
||||
|
||||
#### alert.start()
|
||||
**Kind**: instance method of [<code>Alert</code>](#module_lib/alert..Alert)
|
|
@ -0,0 +1,29 @@
|
|||
import type { WebContents } from 'electron';
|
||||
/** @module lib/alert */
|
||||
/**
|
||||
* Class for pushing an alert to the UI from the backend.
|
||||
*/
|
||||
export declare class Alert {
|
||||
private ipc;
|
||||
private log;
|
||||
private id;
|
||||
private cb;
|
||||
private ui;
|
||||
constructor(ui: WebContents);
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private init;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private listen;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private listener;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
start(cmd: string): Promise<number>;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Alert = void 0;
|
||||
const electron_1 = require("electron");
|
||||
const log_1 = require("log");
|
||||
/** @module lib/alert */
|
||||
/**
|
||||
* Class for pushing an alert to the UI from the backend.
|
||||
*/
|
||||
class Alert {
|
||||
constructor(ui) {
|
||||
this.ipc = electron_1.ipcMain;
|
||||
this.id = 'alert';
|
||||
this.cb = null;
|
||||
this.ui = ui;
|
||||
this.init();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async init() {
|
||||
this.log = await (0, log_1.Log)({ label: this.id });
|
||||
this.listen();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
listen() {
|
||||
this.ipc.on(this.id, this.listener.bind(this));
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async listener(event, arg) {
|
||||
if (this.cb !== null) {
|
||||
try {
|
||||
await this.cb(arg.state, arg.id);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
event.returnValue = true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async start(cmd) {
|
||||
const start = +new Date();
|
||||
const msg = (cmd + '').replace('ALERT', '').replace('Alert', '').replace('alert', '').trim();
|
||||
this.ui.send(this.id, { msg });
|
||||
return new Promise(function (resolve, reject) {
|
||||
this.cb = function () {
|
||||
const ms = (+new Date()) - start;
|
||||
return resolve(ms);
|
||||
};
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
exports.Alert = Alert;
|
||||
module.exports = { Alert };
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/alert/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEb,uCAAmC;AAEnC,6BAA0B;AAI1B,wBAAwB;AAExB;;GAEG;AAEH,MAAa,KAAK;IAOjB,YAAc,EAAgB;QANtB,QAAG,GAAoB,kBAAO,CAAA;QAE9B,OAAE,GAAY,OAAO,CAAA;QACrB,OAAE,GAAc,IAAI,CAAA;QAI3B,IAAI,CAAC,EAAE,GAAG,EAAE,CAAA;QACZ,IAAI,CAAC,IAAI,EAAE,CAAA;IACZ,CAAC;IAED;;QAEI;IACI,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,GAAG,GAAG,MAAM,IAAA,SAAG,EAAC,EAAE,KAAK,EAAG,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;QACzC,IAAI,CAAC,MAAM,EAAE,CAAA;IACd,CAAC;IAED;;QAEI;IACI,MAAM;QACb,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAC/C,CAAC;IAED;;QAEI;IACI,KAAK,CAAC,QAAQ,CAAE,KAAoB,EAAE,GAAS;QACtD,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE;YACrB,IAAI;gBACH,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;aAChC;YAAC,OAAO,GAAG,EAAE;gBACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;aACnB;SACD;QACD,KAAK,CAAC,WAAW,GAAG,IAAI,CAAA;IACzB,CAAC;IAED;;QAEI;IACG,KAAK,CAAC,KAAK,CAAE,GAAY;QAC/B,MAAM,KAAK,GAAY,CAAC,IAAI,IAAI,EAAE,CAAC;QACnC,MAAM,GAAG,GAAY,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;QACrG,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAA;QAC9B,OAAO,IAAI,OAAO,CAAC,UAAU,OAAkB,EAAE,MAAiB;YACjE,IAAI,CAAC,EAAE,GAAG;gBACT,MAAM,EAAE,GAAY,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC;gBAC1C,OAAO,OAAO,CAAC,EAAE,CAAC,CAAC;YACpB,CAAC,CAAA;QACF,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACf,CAAC;CACD;AAvDD,sBAuDC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,CAAA"}
|
|
@ -0,0 +1,296 @@
|
|||
## Modules
|
||||
|
||||
<dl>
|
||||
<dt><a href="#module_lib/arduino">lib/arduino</a></dt>
|
||||
<dd></dd>
|
||||
</dl>
|
||||
|
||||
## Constants
|
||||
|
||||
<dl>
|
||||
<dt><a href="#delay_1">delay_1</a></dt>
|
||||
<dd><p>2023-07-16 Clarification</p>
|
||||
<p>Previous versions of this script intermingled and even
|
||||
swapped the usage of the terms 'serial' and 'device'.
|
||||
From here on out, the terms will be used as such:</p>
|
||||
<p>serial - a hardware address of a serial port
|
||||
device - common name of a type of mcopy device (eg. camera,
|
||||
projector, light) that is aliased to a serial port</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="module_lib/arduino"></a>
|
||||
|
||||
## lib/arduino
|
||||
|
||||
* [lib/arduino](#module_lib/arduino)
|
||||
* [~Arduino](#module_lib/arduino..Arduino)
|
||||
* [.enumerate()](#module_lib/arduino..Arduino+enumerate) ⇒ <code>Promise</code>
|
||||
* [.sendAsync(device, cmd)](#module_lib/arduino..Arduino+sendAsync) ⇒ <code>Promise</code>
|
||||
* [.send(device, cmd)](#module_lib/arduino..Arduino+send) ⇒ <code>Promise.<(boolean\|string)></code>
|
||||
* [.sendString(device, str)](#module_lib/arduino..Arduino+sendString) ⇒ <code>Promise.<(boolean\|string)></code>
|
||||
* [.stateAsync()](#module_lib/arduino..Arduino+stateAsync)
|
||||
* [.state()](#module_lib/arduino..Arduino+state)
|
||||
* [.writeAsync(device, str)](#module_lib/arduino..Arduino+writeAsync) ⇒ <code>Promise</code>
|
||||
* [.end(serial, data)](#module_lib/arduino..Arduino+end) ⇒ <code>any</code>
|
||||
* [.aliasSerial(device, serial)](#module_lib/arduino..Arduino+aliasSerial)
|
||||
* [.connect(device, serial, confirm)](#module_lib/arduino..Arduino+connect) ⇒ <code>Promise.<string></code>
|
||||
* [.confirmEnd(data)](#module_lib/arduino..Arduino+confirmEnd)
|
||||
* [.verify()](#module_lib/arduino..Arduino+verify) ⇒ <code>Promise.<boolean></code>
|
||||
* [.distinguish()](#module_lib/arduino..Arduino+distinguish) ⇒ <code>Promise.<string></code>
|
||||
* [.close()](#module_lib/arduino..Arduino+close) ⇒ <code>Promise.<boolean></code>
|
||||
* [.fakeConnect(serial)](#module_lib/arduino..Arduino+fakeConnect) ⇒ <code>Promise.<boolean></code>
|
||||
* [.openArduino(device)](#module_lib/arduino..Arduino+openArduino) ⇒ <code>Promise</code>
|
||||
* [.closeArduino(device)](#module_lib/arduino..Arduino+closeArduino) ⇒ <code>Promise</code>
|
||||
|
||||
<a name="module_lib/arduino..Arduino"></a>
|
||||
|
||||
### lib/arduino~Arduino
|
||||
Class representing the arduino communication features.
|
||||
|
||||
**Kind**: inner class of [<code>lib/arduino</code>](#module_lib/arduino)
|
||||
|
||||
* [~Arduino](#module_lib/arduino..Arduino)
|
||||
* [.enumerate()](#module_lib/arduino..Arduino+enumerate) ⇒ <code>Promise</code>
|
||||
* [.sendAsync(device, cmd)](#module_lib/arduino..Arduino+sendAsync) ⇒ <code>Promise</code>
|
||||
* [.send(device, cmd)](#module_lib/arduino..Arduino+send) ⇒ <code>Promise.<(boolean\|string)></code>
|
||||
* [.sendString(device, str)](#module_lib/arduino..Arduino+sendString) ⇒ <code>Promise.<(boolean\|string)></code>
|
||||
* [.stateAsync()](#module_lib/arduino..Arduino+stateAsync)
|
||||
* [.state()](#module_lib/arduino..Arduino+state)
|
||||
* [.writeAsync(device, str)](#module_lib/arduino..Arduino+writeAsync) ⇒ <code>Promise</code>
|
||||
* [.end(serial, data)](#module_lib/arduino..Arduino+end) ⇒ <code>any</code>
|
||||
* [.aliasSerial(device, serial)](#module_lib/arduino..Arduino+aliasSerial)
|
||||
* [.connect(device, serial, confirm)](#module_lib/arduino..Arduino+connect) ⇒ <code>Promise.<string></code>
|
||||
* [.confirmEnd(data)](#module_lib/arduino..Arduino+confirmEnd)
|
||||
* [.verify()](#module_lib/arduino..Arduino+verify) ⇒ <code>Promise.<boolean></code>
|
||||
* [.distinguish()](#module_lib/arduino..Arduino+distinguish) ⇒ <code>Promise.<string></code>
|
||||
* [.close()](#module_lib/arduino..Arduino+close) ⇒ <code>Promise.<boolean></code>
|
||||
* [.fakeConnect(serial)](#module_lib/arduino..Arduino+fakeConnect) ⇒ <code>Promise.<boolean></code>
|
||||
* [.openArduino(device)](#module_lib/arduino..Arduino+openArduino) ⇒ <code>Promise</code>
|
||||
* [.closeArduino(device)](#module_lib/arduino..Arduino+closeArduino) ⇒ <code>Promise</code>
|
||||
|
||||
<a name="module_lib/arduino..Arduino+enumerate"></a>
|
||||
|
||||
#### arduino.enumerate() ⇒ <code>Promise</code>
|
||||
Enumerate all connected devices that might be Arduinos
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
**Returns**: <code>Promise</code> - Resolves after enumerating
|
||||
<a name="module_lib/arduino..Arduino+sendAsync"></a>
|
||||
|
||||
#### arduino.sendAsync(device, cmd) ⇒ <code>Promise</code>
|
||||
Send a command to an Arduino using async/await
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
**Returns**: <code>Promise</code> - Resolves after sending
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| device | <code>string</code> | The Arduino device identifier |
|
||||
| cmd | <code>string</code> | Single character command to send |
|
||||
|
||||
<a name="module_lib/arduino..Arduino+send"></a>
|
||||
|
||||
#### arduino.send(device, cmd) ⇒ <code>Promise.<(boolean\|string)></code>
|
||||
Sends a command to the specified Arduino and waits for a response.
|
||||
Handles the communication lock to prevent sending multiple commands simultaneously.
|
||||
Emits an 'arduino_send' event after successfully sending the command.
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
**Returns**: <code>Promise.<(boolean\|string)></code> - Returns 'false' if the communication is locked, otherwise returns the response from the device.
|
||||
**Throws**:
|
||||
|
||||
- <code>Error</code> Throws an error if the sendAsync method encounters an error.
|
||||
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| device | <code>string</code> | The Arduino device identifier. |
|
||||
| cmd | <code>string</code> | The command to be sent to the Arduino. |
|
||||
|
||||
<a name="module_lib/arduino..Arduino+sendString"></a>
|
||||
|
||||
#### arduino.sendString(device, str) ⇒ <code>Promise.<(boolean\|string)></code>
|
||||
Sends a string to the specified Arduino.
|
||||
Handles different types of devices, including fake devices for testing purposes.
|
||||
Waits for a specified delay before sending the string.
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
**Returns**: <code>Promise.<(boolean\|string)></code> - Returns 'true' if the string is sent successfully, otherwise returns an error message.
|
||||
**Throws**:
|
||||
|
||||
- <code>Error</code> Throws an error if the writeAsync method encounters an error.
|
||||
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| device | <code>string</code> | The Arduino device identifier. |
|
||||
| str | <code>string</code> | The string to be sent to the Arduino. |
|
||||
|
||||
<a name="module_lib/arduino..Arduino+stateAsync"></a>
|
||||
|
||||
#### arduino.stateAsync()
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
<a name="module_lib/arduino..Arduino+state"></a>
|
||||
|
||||
#### arduino.state()
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
<a name="module_lib/arduino..Arduino+writeAsync"></a>
|
||||
|
||||
#### arduino.writeAsync(device, str) ⇒ <code>Promise</code>
|
||||
Send a string to an Arduino using async/await
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
**Returns**: <code>Promise</code> - Resolves after sending
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| device | <code>string</code> | Arduino identifier |
|
||||
| str | <code>string</code> | String to send |
|
||||
|
||||
<a name="module_lib/arduino..Arduino+end"></a>
|
||||
|
||||
#### arduino.end(serial, data) ⇒ <code>any</code>
|
||||
Handles the end of communication with the Arduino.
|
||||
Calculates the time taken for the communication, executes the callback,
|
||||
and emits an 'arduino_end' event. Handles errors and stray data received.
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
**Returns**: <code>any</code> - The time taken for the communication in milliseconds.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| serial | <code>string</code> | The serial address of the Arduino device. |
|
||||
| data | <code>string</code> | The data received from the Arduino. |
|
||||
|
||||
<a name="module_lib/arduino..Arduino+aliasSerial"></a>
|
||||
|
||||
#### arduino.aliasSerial(device, serial)
|
||||
Associates an alias with an Arduinos serial address.
|
||||
Used to map multi-purpose devices onto the same serial connection.
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| device | <code>string</code> | The serial number of the target Arduino. |
|
||||
| serial | <code>string</code> | The alias to be associated with the target device. |
|
||||
|
||||
<a name="module_lib/arduino..Arduino+connect"></a>
|
||||
|
||||
#### arduino.connect(device, serial, confirm) ⇒ <code>Promise.<string></code>
|
||||
Connects to an Arduino using its serial number.
|
||||
Sets up the SerialPort instance and path for the device, and handles data communication.
|
||||
Handles opening the connection and emitting 'arduino_end' or 'confirmEnd' events upon receiving data.
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
**Returns**: <code>Promise.<string></code> - Resolves with the device path if the connection is successful.
|
||||
**Throws**:
|
||||
|
||||
- <code>Error</code> Rejects with an error message if the connection fails.
|
||||
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| device | <code>string</code> | The device identifier (common name). |
|
||||
| serial | <code>string</code> | The serial address of the target Arduino (e.g., COM port on Windows). |
|
||||
| confirm | <code>function</code> | A callback function to be executed upon receiving confirmation data. |
|
||||
|
||||
<a name="module_lib/arduino..Arduino+confirmEnd"></a>
|
||||
|
||||
#### arduino.confirmEnd(data)
|
||||
Handles the confirmation data received from an Arduino.
|
||||
Executes the confirmation callback function if the received data is present in the list of expected values.
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| data | <code>string</code> | The data received from the Arduino. |
|
||||
|
||||
<a name="module_lib/arduino..Arduino+verify"></a>
|
||||
|
||||
#### arduino.verify() ⇒ <code>Promise.<boolean></code>
|
||||
Verifies the connection to an Arduino by sending a connect command.
|
||||
The confirmation callback checks if the received data matches the expected connect command.
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
**Returns**: <code>Promise.<boolean></code> - Resolves with 'true' if the connection is verified successfully.
|
||||
**Throws**:
|
||||
|
||||
- <code>Error</code> Rejects with an error message if the connection verification fails.
|
||||
|
||||
<a name="module_lib/arduino..Arduino+distinguish"></a>
|
||||
|
||||
#### arduino.distinguish() ⇒ <code>Promise.<string></code>
|
||||
Distinguishes the type of Arduino connected.
|
||||
Sends a command to the device to identify its type and resolves the promise with the received type.
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
**Returns**: <code>Promise.<string></code> - Resolves with the type of the connected Arduino-based device.
|
||||
**Throws**:
|
||||
|
||||
- <code>Error</code> Rejects with an error message if the distinguish operation fails.
|
||||
|
||||
<a name="module_lib/arduino..Arduino+close"></a>
|
||||
|
||||
#### arduino.close() ⇒ <code>Promise.<boolean></code>
|
||||
Closes the connection to an Arduino.
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
**Returns**: <code>Promise.<boolean></code> - Resolves with 'true' if the connection is closed successfully.
|
||||
**Throws**:
|
||||
|
||||
- <code>Error</code> Throws an error if the closeArduino method encounters an error.
|
||||
|
||||
<a name="module_lib/arduino..Arduino+fakeConnect"></a>
|
||||
|
||||
#### arduino.fakeConnect(serial) ⇒ <code>Promise.<boolean></code>
|
||||
Establishes a fake connection to an Arduino for testing purposes.
|
||||
Creates a fake SerialPort instance with custom write and string methods.
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
**Returns**: <code>Promise.<boolean></code> - Resolves with 'true' if the fake connection is established successfully.
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| serial | <code>string</code> | The device identifier of the fake Arduino. |
|
||||
|
||||
<a name="module_lib/arduino..Arduino+openArduino"></a>
|
||||
|
||||
#### arduino.openArduino(device) ⇒ <code>Promise</code>
|
||||
Connect to an Arduino using async/await
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
**Returns**: <code>Promise</code> - Resolves after opening
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| device | <code>string</code> | Arduino identifier |
|
||||
|
||||
<a name="module_lib/arduino..Arduino+closeArduino"></a>
|
||||
|
||||
#### arduino.closeArduino(device) ⇒ <code>Promise</code>
|
||||
Close a connection to an Arduino using async/await
|
||||
|
||||
**Kind**: instance method of [<code>Arduino</code>](#module_lib/arduino..Arduino)
|
||||
**Returns**: <code>Promise</code> - Resolves after closing
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| device | <code>string</code> | Arduino identifier |
|
||||
|
||||
<a name="delay_1"></a>
|
||||
|
||||
## delay\_1
|
||||
2023-07-16 Clarification
|
||||
|
||||
Previous versions of this script intermingled and even
|
||||
swapped the usage of the terms 'serial' and 'device'.
|
||||
From here on out, the terms will be used as such:
|
||||
|
||||
serial - a hardware address of a serial port
|
||||
device - common name of a type of mcopy device (eg. camera,
|
||||
projector, light) that is aliased to a serial port
|
||||
|
||||
**Kind**: global constant
|
|
@ -0,0 +1,179 @@
|
|||
/// <reference types="node" />
|
||||
import type { EventEmitter } from 'events';
|
||||
import type { Config } from 'cfg';
|
||||
/** @module lib/arduino */
|
||||
/**
|
||||
* Class representing the arduino communication features.
|
||||
*/
|
||||
export declare class Arduino {
|
||||
private log;
|
||||
private eventEmitter;
|
||||
private cfg;
|
||||
private path;
|
||||
private known;
|
||||
private serial;
|
||||
private baud;
|
||||
private queue;
|
||||
private timer;
|
||||
private locks;
|
||||
private confirmExec;
|
||||
private errorState;
|
||||
private keys;
|
||||
private values;
|
||||
alias: any;
|
||||
stateStr: any;
|
||||
hasState: any;
|
||||
constructor(cfg: Config, ee: EventEmitter, errorState: Function);
|
||||
init(): Promise<void>;
|
||||
/**
|
||||
* Enumerate all connected devices that might be Arduinos
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise} Resolves after enumerating
|
||||
**/
|
||||
enumerate(): Promise<string[]>;
|
||||
/**
|
||||
* Send a command to an Arduino using async/await
|
||||
*
|
||||
* @param {string} device The Arduino device identifier
|
||||
* @param {string} cmd Single character command to send
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise} Resolves after sending
|
||||
**/
|
||||
private sendAsync;
|
||||
/**
|
||||
* Sends a command to the specified Arduino and waits for a response.
|
||||
* Handles the communication lock to prevent sending multiple commands simultaneously.
|
||||
* Emits an 'arduino_send' event after successfully sending the command.
|
||||
*
|
||||
* @async
|
||||
* @param {string} device - The Arduino device identifier.
|
||||
* @param {string} cmd - The command to be sent to the Arduino.
|
||||
* @returns {Promise<boolean|string>} Returns 'false' if the communication is locked, otherwise returns the response from the device.
|
||||
* @throws {Error} Throws an error if the sendAsync method encounters an error.
|
||||
**/
|
||||
send(device: string, cmd: string): Promise<number>;
|
||||
/**
|
||||
* Sends a string to the specified Arduino.
|
||||
* Handles different types of devices, including fake devices for testing purposes.
|
||||
* Waits for a specified delay before sending the string.
|
||||
*
|
||||
* @async
|
||||
* @param {string} device - The Arduino device identifier.
|
||||
* @param {string} str - The string to be sent to the Arduino.
|
||||
* @returns {Promise<boolean|string>} Returns 'true' if the string is sent successfully, otherwise returns an error message.
|
||||
* @throws {Error} Throws an error if the writeAsync method encounters an error.
|
||||
**/
|
||||
sendString(device: string, str: string): Promise<number>;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private stateAsync;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
state(device: string, confirm?: boolean): Promise<string>;
|
||||
/**
|
||||
* Send a string to an Arduino using async/await
|
||||
*
|
||||
* @param {string} device Arduino identifier
|
||||
* @param {string} str String to send
|
||||
*
|
||||
* @returns {Promise} Resolves after sending
|
||||
**/
|
||||
private writeAsync;
|
||||
/**
|
||||
* Handles the end of communication with the Arduino.
|
||||
* Calculates the time taken for the communication, executes the callback,
|
||||
* and emits an 'arduino_end' event. Handles errors and stray data received.
|
||||
*
|
||||
* @param {string} serial - The serial address of the Arduino device.
|
||||
* @param {string} data - The data received from the Arduino.
|
||||
* @returns {any} The time taken for the communication in milliseconds.
|
||||
**/
|
||||
private end;
|
||||
private error;
|
||||
/**
|
||||
* Associates an alias with an Arduinos serial address.
|
||||
* Used to map multi-purpose devices onto the same serial connection.
|
||||
*
|
||||
* @param {string} device - The serial number of the target Arduino.
|
||||
* @param {string} serial - The alias to be associated with the target device.
|
||||
**/
|
||||
aliasSerial(device: string, serial: string): void;
|
||||
/**
|
||||
* Connects to an Arduino using its serial number.
|
||||
* Sets up the SerialPort instance and path for the device, and handles data communication.
|
||||
* Handles opening the connection and emitting 'arduino_end' or 'confirmEnd' events upon receiving data.
|
||||
*
|
||||
* @async
|
||||
* @param {string} device - The device identifier (common name).
|
||||
* @param {string} serial - The serial address of the target Arduino (e.g., COM port on Windows).
|
||||
* @param {function} confirm - A callback function to be executed upon receiving confirmation data.
|
||||
* @returns {Promise<string>} Resolves with the device path if the connection is successful.
|
||||
* @throws {Error} Rejects with an error message if the connection fails.
|
||||
**/
|
||||
connect(device: string, serial: string, confirm: any): Promise<any>;
|
||||
/**
|
||||
* Handles the confirmation data received from an Arduino.
|
||||
* Executes the confirmation callback function if the received data is present in the list of expected values.
|
||||
*
|
||||
* @param {string} data - The data received from the Arduino.
|
||||
**/
|
||||
private confirmEnd;
|
||||
/**
|
||||
* Verifies the connection to an Arduino by sending a connect command.
|
||||
* The confirmation callback checks if the received data matches the expected connect command.
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise<boolean>} Resolves with 'true' if the connection is verified successfully.
|
||||
* @throws {Error} Rejects with an error message if the connection verification fails.
|
||||
**/
|
||||
verify(): Promise<unknown>;
|
||||
/**
|
||||
* Distinguishes the type of Arduino connected.
|
||||
* Sends a command to the device to identify its type and resolves the promise with the received type.
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise<string>} Resolves with the type of the connected Arduino-based device.
|
||||
* @throws {Error} Rejects with an error message if the distinguish operation fails.
|
||||
**/
|
||||
distinguish(): Promise<string>;
|
||||
/**
|
||||
* Closes the connection to an Arduino.
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise<boolean>} Resolves with 'true' if the connection is closed successfully.
|
||||
* @throws {Error} Throws an error if the closeArduino method encounters an error.
|
||||
**/
|
||||
close(): Promise<boolean>;
|
||||
/**
|
||||
* Establishes a fake connection to an Arduino for testing purposes.
|
||||
* Creates a fake SerialPort instance with custom write and string methods.
|
||||
*
|
||||
* @async
|
||||
* @param {string} serial - The device identifier of the fake Arduino.
|
||||
* @returns {Promise<boolean>} Resolves with 'true' if the fake connection is established successfully.
|
||||
**/
|
||||
fakeConnect(device: string): Promise<boolean>;
|
||||
/**
|
||||
* Connect to an Arduino using async/await
|
||||
*
|
||||
* @param {string} device Arduino identifier
|
||||
*
|
||||
* @returns {Promise} Resolves after opening
|
||||
**/
|
||||
private openArduino;
|
||||
/**
|
||||
* Close a connection to an Arduino using async/await
|
||||
*
|
||||
* @param {string} device Arduino identifier
|
||||
*
|
||||
* @returns {Promise} Resolves after closing
|
||||
**/
|
||||
private closeArduino;
|
||||
private lock;
|
||||
private unlock;
|
||||
private isLocked;
|
||||
}
|
|
@ -1,327 +1,597 @@
|
|||
'use strict'
|
||||
|
||||
const SerialPort = require('serialport')
|
||||
const Readline = SerialPort.parsers.Readline
|
||||
const exec = require('child_process').exec
|
||||
const parser = new Readline('')
|
||||
const newlineRe = new RegExp('\n', 'g')
|
||||
const returnRe = new RegExp('\r', 'g')
|
||||
let eventEmitter
|
||||
|
||||
const mcopy = {}
|
||||
|
||||
async function delay (ms) {
|
||||
return new Promise(resolve => {
|
||||
return setTimeout(resolve, ms)
|
||||
})
|
||||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Arduino = void 0;
|
||||
/**
|
||||
* 2023-07-16 Clarification
|
||||
*
|
||||
* Previous versions of this script intermingled and even
|
||||
* swapped the usage of the terms 'serial' and 'device'.
|
||||
* From here on out, the terms will be used as such:
|
||||
*
|
||||
* serial - a hardware address of a serial port
|
||||
* device - common name of a type of mcopy device (eg. camera,
|
||||
* projector, light) that is aliased to a serial port
|
||||
*
|
||||
**/
|
||||
const delay_1 = require("delay");
|
||||
const log_1 = require("log");
|
||||
const { SerialPort } = require('serialport');
|
||||
const { ReadlineParser } = require('@serialport/parser-readline');
|
||||
const parser = new ReadlineParser({ delimiter: '\r\n' });
|
||||
const newlineRe = new RegExp('\n', 'g');
|
||||
const returnRe = new RegExp('\r', 'g');
|
||||
const KNOWN = [
|
||||
'/dev/tty.usbmodem1a161',
|
||||
'/dev/tty.usbserial-A800f8dk',
|
||||
'/dev/tty.usbserial-A900cebm',
|
||||
'/dev/tty.usbmodem1a131',
|
||||
'/dev/tty.usbserial-a900f6de',
|
||||
'/dev/tty.usbmodem1a141',
|
||||
'/dev/ttyACM0',
|
||||
'COM3'
|
||||
];
|
||||
/** @module lib/arduino */
|
||||
/**
|
||||
* Class representing the arduino communication features.
|
||||
*/
|
||||
class Arduino {
|
||||
constructor(cfg, ee, errorState) {
|
||||
this.path = {};
|
||||
this.known = KNOWN;
|
||||
this.serial = {};
|
||||
this.baud = 57600;
|
||||
this.queue = {};
|
||||
this.timer = 0;
|
||||
this.locks = {};
|
||||
this.alias = {};
|
||||
this.stateStr = {};
|
||||
this.hasState = {};
|
||||
this.cfg = cfg;
|
||||
this.eventEmitter = ee;
|
||||
this.errorState = errorState;
|
||||
this.init();
|
||||
}
|
||||
async init() {
|
||||
this.log = await (0, log_1.Log)({ label: 'arduino' });
|
||||
this.keys = Object.keys(this.cfg.arduino.cmd);
|
||||
this.values = this.keys.map((key) => this.cfg.arduino.cmd[key]);
|
||||
}
|
||||
/**
|
||||
* Enumerate all connected devices that might be Arduinos
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise} Resolves after enumerating
|
||||
**/
|
||||
async enumerate() {
|
||||
let ports;
|
||||
let matches = [];
|
||||
try {
|
||||
ports = await SerialPort.list();
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
this.log.info('Available ports:');
|
||||
this.log.info(ports.map((port) => { return port.path; }).join(','));
|
||||
ports.forEach((port) => {
|
||||
if (this.known.indexOf(port.path) !== -1) {
|
||||
matches.push(port.path);
|
||||
}
|
||||
else if ((port.manufacturer + '').toLowerCase().indexOf('arduino') !== -1) {
|
||||
matches.push(port.path);
|
||||
}
|
||||
else if ((port.path + '').toLowerCase().indexOf('usbserial') !== -1) {
|
||||
matches.push(port.path);
|
||||
}
|
||||
else if ((port.path + '').toLowerCase().indexOf('usbmodem') !== -1) {
|
||||
matches.push(port.path);
|
||||
}
|
||||
else if ((port.path + '').toLowerCase().indexOf('ttyusb') !== -1) {
|
||||
matches.push(port.path);
|
||||
}
|
||||
});
|
||||
if (matches.length === 0) {
|
||||
throw new Error('No USB devices found');
|
||||
}
|
||||
else if (matches.length > 0) {
|
||||
return matches;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Send a command to an Arduino using async/await
|
||||
*
|
||||
* @param {string} device The Arduino device identifier
|
||||
* @param {string} cmd Single character command to send
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise} Resolves after sending
|
||||
**/
|
||||
async sendAsync(device, cmd) {
|
||||
return new Promise((resolve, reject) => {
|
||||
//this.log.info(`sendAsync ${cmd} -> ${device}`)
|
||||
this.queue[cmd] = (ms) => {
|
||||
return resolve(ms);
|
||||
};
|
||||
//this.log.info(`Device: ${device}`)
|
||||
return this.serial[this.alias[device]].write(cmd, (err, results) => {
|
||||
if (err) {
|
||||
//this.log.error(err)
|
||||
return reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Sends a command to the specified Arduino and waits for a response.
|
||||
* Handles the communication lock to prevent sending multiple commands simultaneously.
|
||||
* Emits an 'arduino_send' event after successfully sending the command.
|
||||
*
|
||||
* @async
|
||||
* @param {string} device - The Arduino device identifier.
|
||||
* @param {string} cmd - The command to be sent to the Arduino.
|
||||
* @returns {Promise<boolean|string>} Returns 'false' if the communication is locked, otherwise returns the response from the device.
|
||||
* @throws {Error} Throws an error if the sendAsync method encounters an error.
|
||||
**/
|
||||
async send(device, cmd) {
|
||||
const serial = this.alias[device];
|
||||
let ms;
|
||||
this.log.info(`send ${cmd} -> ${device}`);
|
||||
if (this.isLocked(serial)) {
|
||||
this.log.error(`send Serial ${serial} is locked`);
|
||||
return 0;
|
||||
}
|
||||
this.timer = new Date().getTime();
|
||||
this.lock(serial);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
try {
|
||||
ms = await this.sendAsync(device, cmd);
|
||||
}
|
||||
catch (e) {
|
||||
this.log.error(`Failed to send to ${device} @ ${serial}`, e);
|
||||
return 0;
|
||||
}
|
||||
this.unlock(serial);
|
||||
await this.eventEmitter.emit('arduino_send', cmd);
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Sends a string to the specified Arduino.
|
||||
* Handles different types of devices, including fake devices for testing purposes.
|
||||
* Waits for a specified delay before sending the string.
|
||||
*
|
||||
* @async
|
||||
* @param {string} device - The Arduino device identifier.
|
||||
* @param {string} str - The string to be sent to the Arduino.
|
||||
* @returns {Promise<boolean|string>} Returns 'true' if the string is sent successfully, otherwise returns an error message.
|
||||
* @throws {Error} Throws an error if the writeAsync method encounters an error.
|
||||
**/
|
||||
async sendString(device, str) {
|
||||
let ms;
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (typeof this.serial[this.alias[device]].fake !== 'undefined'
|
||||
&& this.serial[this.alias[device]].fake) {
|
||||
return this.serial[this.alias[device]].string(str);
|
||||
}
|
||||
else {
|
||||
this.log.info(`sendString ${str} -> ${device}`);
|
||||
try {
|
||||
ms = await this.writeAsync(device, str);
|
||||
}
|
||||
catch (e) {
|
||||
this.log.error(`Error sending string to ${device}`, e);
|
||||
return 0;
|
||||
}
|
||||
this.unlock(this.alias[device]);
|
||||
return ms;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async stateAsync(device, confirm = false) {
|
||||
const cmd = this.cfg.arduino.cmd.state;
|
||||
const serial = confirm ? this.alias['connect'] : this.alias[device];
|
||||
return new Promise((resolve, reject) => {
|
||||
this.queue[cmd] = (state) => {
|
||||
this.stateStr[device] = state;
|
||||
if (confirm) {
|
||||
this.hasState[device] = true;
|
||||
this.log.info(`Device ${device} supports state [${state}]`);
|
||||
}
|
||||
return resolve(state);
|
||||
};
|
||||
if (confirm) {
|
||||
setTimeout(function () {
|
||||
if (typeof this.queue[cmd] !== 'undefined') {
|
||||
delete this.queue[cmd];
|
||||
this.hasState[device] = false;
|
||||
this.log.info(`Device ${device} does not support state`);
|
||||
return resolve(null);
|
||||
}
|
||||
}.bind(this), 1000);
|
||||
}
|
||||
this.log.info(`stateAsync ${cmd} -> ${device}`);
|
||||
return this.serial[serial].write(cmd, (err, results) => {
|
||||
if (err) {
|
||||
//this.log.error(err)
|
||||
return reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async state(device, confirm = false) {
|
||||
const serial = confirm ? this.alias['connect'] : this.alias[device];
|
||||
let results;
|
||||
if (this.isLocked(serial)) {
|
||||
this.log.warn(`state Serial ${serial} is locked`);
|
||||
return null;
|
||||
}
|
||||
this.timer = new Date().getTime();
|
||||
this.lock(serial);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
try {
|
||||
results = await this.stateAsync(device, confirm);
|
||||
}
|
||||
catch (e) {
|
||||
this.log.error(`Error getting state from ${device}`, e);
|
||||
return null;
|
||||
}
|
||||
this.unlock(serial);
|
||||
await this.eventEmitter.emit('arduino_state', this.cfg.arduino.cmd.state);
|
||||
return results;
|
||||
}
|
||||
/**
|
||||
* Send a string to an Arduino using async/await
|
||||
*
|
||||
* @param {string} device Arduino identifier
|
||||
* @param {string} str String to send
|
||||
*
|
||||
* @returns {Promise} Resolves after sending
|
||||
**/
|
||||
async writeAsync(device, str) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.serial[this.alias[device]].write(str, function (err, results) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(results);
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Handles the end of communication with the Arduino.
|
||||
* Calculates the time taken for the communication, executes the callback,
|
||||
* and emits an 'arduino_end' event. Handles errors and stray data received.
|
||||
*
|
||||
* @param {string} serial - The serial address of the Arduino device.
|
||||
* @param {string} data - The data received from the Arduino.
|
||||
* @returns {any} The time taken for the communication in milliseconds.
|
||||
**/
|
||||
end(serial, data) {
|
||||
const end = new Date().getTime();
|
||||
const ms = end - this.timer;
|
||||
let complete;
|
||||
//this.log.info(`end ${serial} -> ${data}`)
|
||||
if (this.queue[data] !== undefined) {
|
||||
this.unlock(serial);
|
||||
complete = this.queue[data](ms); //execute callback
|
||||
this.eventEmitter.emit('arduino_end', data);
|
||||
delete this.queue[data];
|
||||
}
|
||||
else if (data[0] === this.cfg.arduino.cmd.state) {
|
||||
//this.log.info(`end serial -> ${serial}`)
|
||||
this.unlock(serial);
|
||||
complete = this.queue[this.cfg.arduino.cmd.state](data);
|
||||
this.eventEmitter.emit('arduino_end', data);
|
||||
delete this.queue[this.cfg.arduino.cmd.state];
|
||||
return data;
|
||||
}
|
||||
else if (data[0] === this.cfg.arduino.cmd.error) {
|
||||
this.log.error(`Received error from device ${serial}`);
|
||||
this.unlock(serial);
|
||||
this.error(serial, data);
|
||||
//error state
|
||||
//stop sequence
|
||||
//throw error in ui
|
||||
}
|
||||
else {
|
||||
this.log.info('Received stray "' + data + '"'); //silent to user
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
error(serial, data) {
|
||||
this.log.error("ERROR", data);
|
||||
}
|
||||
/**
|
||||
* Associates an alias with an Arduinos serial address.
|
||||
* Used to map multi-purpose devices onto the same serial connection.
|
||||
*
|
||||
* @param {string} device - The serial number of the target Arduino.
|
||||
* @param {string} serial - The alias to be associated with the target device.
|
||||
**/
|
||||
aliasSerial(device, serial) {
|
||||
//this.log.info(`Making "${serial}" an alias of ${device}`)
|
||||
this.alias[device] = serial;
|
||||
}
|
||||
/**
|
||||
* Connects to an Arduino using its serial number.
|
||||
* Sets up the SerialPort instance and path for the device, and handles data communication.
|
||||
* Handles opening the connection and emitting 'arduino_end' or 'confirmEnd' events upon receiving data.
|
||||
*
|
||||
* @async
|
||||
* @param {string} device - The device identifier (common name).
|
||||
* @param {string} serial - The serial address of the target Arduino (e.g., COM port on Windows).
|
||||
* @param {function} confirm - A callback function to be executed upon receiving confirmation data.
|
||||
* @returns {Promise<string>} Resolves with the device path if the connection is successful.
|
||||
* @throws {Error} Rejects with an error message if the connection fails.
|
||||
**/
|
||||
async connect(device, serial, confirm) {
|
||||
//this.log.info(`connect device ${device}`)
|
||||
//this.log.info(`connect serial ${serial}`)
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let connectSuccess;
|
||||
this.path[device] = serial;
|
||||
this.aliasSerial(device, serial);
|
||||
this.serial[serial] = new SerialPort({
|
||||
path: serial,
|
||||
autoOpen: false,
|
||||
baudRate: this.cfg.arduino.baud,
|
||||
parser
|
||||
});
|
||||
this.unlock(serial);
|
||||
try {
|
||||
connectSuccess = await this.openArduino(device);
|
||||
}
|
||||
catch (e) {
|
||||
this.log.error(`Failed to open ${device} @ ${serial}: ` + e);
|
||||
return reject(e);
|
||||
}
|
||||
this.log.info(`Opened connection with ${this.path[device]} as ${device}`);
|
||||
if (!confirm) {
|
||||
this.serial[this.alias[device]].on('data', async (data) => {
|
||||
let d = data.toString('utf8');
|
||||
d = d.replace(newlineRe, '').replace(returnRe, '');
|
||||
return this.end(serial, d);
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.serial[this.alias[device]].on('data', async (data) => {
|
||||
let d = data.toString('utf8');
|
||||
d = d.replace(newlineRe, '').replace(returnRe, '');
|
||||
return await this.confirmEnd(d);
|
||||
});
|
||||
}
|
||||
return resolve(this.path[serial]);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Handles the confirmation data received from an Arduino.
|
||||
* Executes the confirmation callback function if the received data is present in the list of expected values.
|
||||
*
|
||||
* @param {string} data - The data received from the Arduino.
|
||||
**/
|
||||
confirmEnd(data) {
|
||||
if (this.values.indexOf(data) !== -1 && typeof this.confirmExec === 'function') {
|
||||
this.confirmExec(null, data);
|
||||
this.confirmExec = null;
|
||||
this.unlock(this.alias['connect']);
|
||||
}
|
||||
else if (data[0] === this.cfg.arduino.cmd.state) {
|
||||
this.queue[this.cfg.arduino.cmd.state](data);
|
||||
delete this.queue[this.cfg.arduino.cmd.state];
|
||||
this.unlock(this.alias['connect']);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Verifies the connection to an Arduino by sending a connect command.
|
||||
* The confirmation callback checks if the received data matches the expected connect command.
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise<boolean>} Resolves with 'true' if the connection is verified successfully.
|
||||
* @throws {Error} Rejects with an error message if the connection verification fails.
|
||||
**/
|
||||
async verify() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const device = 'connect';
|
||||
let writeSuccess;
|
||||
this.confirmExec = function (err, data) {
|
||||
if (data === this.cfg.arduino.cmd.connect) {
|
||||
return resolve(true);
|
||||
}
|
||||
else {
|
||||
return reject('Wrong data returned');
|
||||
}
|
||||
};
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
try {
|
||||
writeSuccess = await this.sendAsync(device, this.cfg.arduino.cmd.connect);
|
||||
}
|
||||
catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
return resolve(writeSuccess);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Distinguishes the type of Arduino connected.
|
||||
* Sends a command to the device to identify its type and resolves the promise with the received type.
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise<string>} Resolves with the type of the connected Arduino-based device.
|
||||
* @throws {Error} Rejects with an error message if the distinguish operation fails.
|
||||
**/
|
||||
async distinguish() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const device = 'connect';
|
||||
let writeSuccess;
|
||||
let type;
|
||||
this.confirmExec = function (err, data) {
|
||||
if (data === this.cfg.arduino.cmd.projector_identifier) {
|
||||
type = 'projector';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.camera_identifier) {
|
||||
type = 'camera';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.light_identifier) {
|
||||
type = 'light';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.projector_light_identifier) {
|
||||
type = 'projector,light';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.projector_camera_light_identifier) {
|
||||
type = 'projector,camera,light';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.projector_camera_identifier) {
|
||||
type = 'projector,camera';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.projector_second_identifier) {
|
||||
type = 'projector_second';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.projectors_identifier) {
|
||||
type = 'projector,projector_second';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.camera_second_identifier) {
|
||||
type = 'camera_second';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.cameras_identifier) {
|
||||
type = 'camera,camera_second';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.camera_projectors_identifier) {
|
||||
type = 'camera,projector,projector_second';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.cameras_projector_identifier) {
|
||||
type = 'camera,camera_second,projector';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.cameras_projectors_identifier) {
|
||||
type = 'camera,camera_second,projector,projector_second';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.capper_identifier) {
|
||||
type = 'capper';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.camera_capper_identifier) {
|
||||
type = 'camera,capper';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.camera_capper_projector_identifier) {
|
||||
type = 'camera,capper,projector';
|
||||
}
|
||||
else if (data === this.cfg.arduino.cmd.camera_capper_projectors_identifier) {
|
||||
type = 'camera,capper,projector,projector_second';
|
||||
}
|
||||
return resolve(type);
|
||||
};
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
try {
|
||||
writeSuccess = await this.sendAsync(device, this.cfg.arduino.cmd.mcopy_identifier);
|
||||
this.log.info(writeSuccess);
|
||||
}
|
||||
catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Closes the connection to an Arduino.
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise<boolean>} Resolves with 'true' if the connection is closed successfully.
|
||||
* @throws {Error} Throws an error if the closeArduino method encounters an error.
|
||||
**/
|
||||
async close() {
|
||||
const device = 'connect';
|
||||
let closeSuccess;
|
||||
try {
|
||||
closeSuccess = await this.closeArduino(device);
|
||||
}
|
||||
catch (e) {
|
||||
throw e;
|
||||
}
|
||||
return closeSuccess;
|
||||
}
|
||||
/**
|
||||
* Establishes a fake connection to an Arduino for testing purposes.
|
||||
* Creates a fake SerialPort instance with custom write and string methods.
|
||||
*
|
||||
* @async
|
||||
* @param {string} serial - The device identifier of the fake Arduino.
|
||||
* @returns {Promise<boolean>} Resolves with 'true' if the fake connection is established successfully.
|
||||
**/
|
||||
async fakeConnect(device) {
|
||||
const serial = '/dev/fake';
|
||||
this.aliasSerial(device, serial);
|
||||
this.serial[serial] = {
|
||||
write: async function (cmd, cb) {
|
||||
const t = {
|
||||
c: this.cfg.arduino.cam.time + this.cfg.arduino.cam.delay,
|
||||
p: this.cfg.arduino.proj.time + this.cfg.arduino.proj.delay,
|
||||
A: 180,
|
||||
B: 180
|
||||
};
|
||||
let timeout = t[cmd];
|
||||
if (typeof timeout === 'undefined')
|
||||
timeout = 10;
|
||||
this.timer = +new Date();
|
||||
await (0, delay_1.delay)(timeout);
|
||||
this.end(serial, cmd);
|
||||
return cb();
|
||||
}.bind(this),
|
||||
string: async function (str) {
|
||||
//do nothing
|
||||
return true;
|
||||
},
|
||||
fake: true
|
||||
};
|
||||
//this.log.info('Connected to fake arduino! Not real! Does not exist!')
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Connect to an Arduino using async/await
|
||||
*
|
||||
* @param {string} device Arduino identifier
|
||||
*
|
||||
* @returns {Promise} Resolves after opening
|
||||
**/
|
||||
async openArduino(device) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return this.serial[this.alias[device]].open((err) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Close a connection to an Arduino using async/await
|
||||
*
|
||||
* @param {string} device Arduino identifier
|
||||
*
|
||||
* @returns {Promise} Resolves after closing
|
||||
**/
|
||||
async closeArduino(device) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return this.serial[this.alias[device]].close((err) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
lock(serial) {
|
||||
//this.log.info(`Locked serial ${serial}`)
|
||||
this.locks[serial] = true;
|
||||
}
|
||||
unlock(serial) {
|
||||
//this.log.info(`Unlocked serial ${serial}`)
|
||||
this.locks[serial] = false;
|
||||
}
|
||||
isLocked(serial) {
|
||||
return typeof this.locks[serial] !== 'undefined' && this.locks[serial] === true;
|
||||
}
|
||||
}
|
||||
|
||||
async function send (device, cmd) {
|
||||
return new Promise ((resolve, reject) => {
|
||||
mcopy.arduino.queue[cmd] = (ms) => {
|
||||
return resolve(ms)
|
||||
}
|
||||
return mcopy.arduino.serial[device].write(cmd, (err, results) => {
|
||||
if (err) {
|
||||
//console.error(err)
|
||||
return reject(err)
|
||||
}
|
||||
//
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function write (device, str) {
|
||||
return new Promise ((resolve, reject) => {
|
||||
mcopy.arduino.serial[device].write(str, function (err, results) {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
//console.log('sent: ' + str)
|
||||
return resolve(results)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function open (device) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return mcopy.arduino.serial[device].open(error => {
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
return resolve(true)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function close (device) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return mcopy.arduino.serial[device].close((err) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
return resolve(true)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/******
|
||||
Arduino handlers
|
||||
*******/
|
||||
mcopy.arduino = {
|
||||
path : {},
|
||||
known: [
|
||||
'/dev/tty.usbmodem1a161',
|
||||
'/dev/tty.usbserial-A800f8dk',
|
||||
'/dev/tty.usbserial-A900cebm',
|
||||
'/dev/tty.usbmodem1a131',
|
||||
'/dev/tty.usbserial-a900f6de',
|
||||
'/dev/tty.usbmodem1a141',
|
||||
'/dev/ttyACM0',
|
||||
'COM3'
|
||||
],
|
||||
alias : {
|
||||
|
||||
},
|
||||
serial : {
|
||||
connect : {},
|
||||
projector : {},
|
||||
camera : {},
|
||||
light : {}
|
||||
},
|
||||
baud : 57600,
|
||||
queue : {},
|
||||
timer : 0,
|
||||
lock : false
|
||||
}
|
||||
|
||||
mcopy.arduino.enumerate = async function () {
|
||||
return new Promise( (resolve, reject) => {
|
||||
return SerialPort.list((err, ports) => {
|
||||
let matches = []
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
ports.forEach(port => {
|
||||
if (mcopy.arduino.known.indexOf(port.comName) !== -1) {
|
||||
matches.push(port.comName)
|
||||
} else if ((port.manufacturer + '').toLowerCase().indexOf('arduino') !== -1) {
|
||||
matches.push(port.comName)
|
||||
}
|
||||
})
|
||||
if (matches.length === 0) {
|
||||
return reject('No USB devices found');
|
||||
} else if (matches.length > 0) {
|
||||
return resolve(matches)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
//commands which respond to a sent char
|
||||
mcopy.arduino.send = async function (serial, cmd, res) {
|
||||
const device = mcopy.arduino.alias[serial]
|
||||
let results
|
||||
if (mcopy.arduino.lock) {
|
||||
return false
|
||||
}
|
||||
mcopy.arduino.lock = true
|
||||
await delay(mcopy.cfg.arduino.serialDelay)
|
||||
try {
|
||||
results = await send(device, cmd)
|
||||
} catch (e) {
|
||||
return console.error(e)
|
||||
}
|
||||
mcopy.arduino.lock = false
|
||||
mcopy.arduino.timer = new Date().getTime()
|
||||
return await eventEmitter.emit('arduino_send', cmd)
|
||||
}
|
||||
|
||||
//send strings, after char triggers firmware to accept
|
||||
mcopy.arduino.string = async function (serial, str) {
|
||||
const device = mcopy.arduino.alias[serial]
|
||||
let writeSuccess
|
||||
await delay(mcopy.cfg.arduino.serialDelay)
|
||||
if (typeof mcopy.arduino.serial[device].fake !== 'undefined'
|
||||
&& mcopy.arduino.serial[device].fake) {
|
||||
return mcopy.arduino.serial[device].string(str)
|
||||
} else {
|
||||
try {
|
||||
writeSuccess = await write(device, str)
|
||||
} catch (e) {
|
||||
return console.error(e)
|
||||
}
|
||||
return writeSuccess
|
||||
}
|
||||
}
|
||||
|
||||
//respond with same char over serial when done
|
||||
mcopy.arduino.end = async function (data) {
|
||||
const end = new Date().getTime()
|
||||
const ms = end - mcopy.arduino.timer
|
||||
let complete
|
||||
if (mcopy.arduino.queue[data] !== undefined) {
|
||||
mcopy.arduino.lock = false;
|
||||
//console.log('Command ' + data + ' took ' + ms + 'ms');
|
||||
complete = mcopy.arduino.queue[data](ms) //execute callback
|
||||
eventEmitter.emit('arduino_end', data)
|
||||
delete mcopy.arduino.queue[data]
|
||||
} else {
|
||||
//console.log('Received stray "' + data + '"'); //silent to user
|
||||
}
|
||||
return complete
|
||||
};
|
||||
mcopy.arduino.alias = function (serial, device) {
|
||||
console.log(`Making "${serial}" an alias of ${device}`)
|
||||
mcopy.arduino.alias[serial] = device
|
||||
}
|
||||
mcopy.arduino.connect = async function (serial, device, confirm) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let connectSuccess
|
||||
mcopy.arduino.path[serial] = device;
|
||||
mcopy.arduino.alias[serial] = device;
|
||||
mcopy.arduino.serial[device] = new SerialPort(mcopy.arduino.path[serial], {
|
||||
autoOpen : false,
|
||||
baudRate: mcopy.cfg.arduino.baud,
|
||||
parser: parser
|
||||
})
|
||||
try {
|
||||
connectSuccess = await open(device)
|
||||
} catch (e) {
|
||||
console.error('failed to open: ' + e)
|
||||
return reject(e)
|
||||
}
|
||||
console.log(`Opened connection with ${mcopy.arduino.path[serial]} as ${serial}`);
|
||||
if (!confirm) {
|
||||
mcopy.arduino.serial[device].on('data', async (data) => {
|
||||
let d = data.toString('utf8')
|
||||
d = d.replace(newlineRe, '').replace(returnRe, '')
|
||||
return await mcopy.arduino.end(d)
|
||||
})
|
||||
} else {
|
||||
mcopy.arduino.serial[device].on('data', async (data) => {
|
||||
let d = data.toString('utf8')
|
||||
d = d.replace(newlineRe, '').replace(returnRe, '')
|
||||
return await mcopy.arduino.confirmEnd(d)
|
||||
})
|
||||
}
|
||||
return resolve(mcopy.arduino.path[serial])
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
mcopy.arduino.confirmExec = {};
|
||||
mcopy.arduino.confirmEnd = function (data) {
|
||||
//console.dir(data)
|
||||
if (data === mcopy.cfg.arduino.cmd.connect
|
||||
|| data === mcopy.cfg.arduino.cmd.proj_identifier
|
||||
|| data === mcopy.cfg.arduino.cmd.cam_identifier
|
||||
|| data === mcopy.cfg.arduino.cmd.light_identifier
|
||||
|| data === mcopy.cfg.arduino.cmd.proj_light_identifier
|
||||
|| data === mcopy.cfg.arduino.cmd.proj_cam_light_identifier
|
||||
|| data === mcopy.cfg.arduino.cmd.proj_cam_identifier ) {
|
||||
mcopy.arduino.confirmExec(null, data);
|
||||
mcopy.arduino.confirmExec = {};
|
||||
}
|
||||
}
|
||||
|
||||
mcopy.arduino.verify = async function () {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const device = mcopy.arduino.alias['connect']
|
||||
let writeSuccess
|
||||
mcopy.arduino.confirmExec = function (err, data) {
|
||||
if (data === mcopy.cfg.arduino.cmd.connect) {
|
||||
return resolve(true)
|
||||
} else {
|
||||
return reject('Wrong data returned')
|
||||
}
|
||||
}
|
||||
await delay(mcopy.cfg.arduino.serialDelay)
|
||||
try {
|
||||
writeSuccess = await send(device, mcopy.cfg.arduino.cmd.connect)
|
||||
} catch (e) {
|
||||
return reject(e)
|
||||
}
|
||||
return resolve(writeSuccess)
|
||||
})
|
||||
}
|
||||
|
||||
mcopy.arduino.distinguish = async function () {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const device = mcopy.arduino.alias['connect']
|
||||
let writeSuccess
|
||||
let type
|
||||
mcopy.arduino.confirmExec = function (err, data) {
|
||||
if (data === mcopy.cfg.arduino.cmd.proj_identifier) {
|
||||
type = 'projector'
|
||||
} else if (data === mcopy.cfg.arduino.cmd.cam_identifier) {
|
||||
type = 'camera'
|
||||
} else if (data === mcopy.cfg.arduino.cmd.light_identifier) {
|
||||
type = 'light'
|
||||
} else if (data === mcopy.cfg.arduino.cmd.proj_light_identifier) {
|
||||
type = 'projector,light'
|
||||
} else if (data === mcopy.cfg.arduino.cmd.proj_cam_light_identifier) {
|
||||
type = 'projector,camera,light'
|
||||
} else if (data === mcopy.cfg.arduino.cmd.proj_cam_identifier) {
|
||||
type = 'projector,camera'
|
||||
}
|
||||
return resolve(type)
|
||||
}
|
||||
await delay(mcopy.cfg.arduino.serialDelay)
|
||||
try {
|
||||
writeSuccess = await send(device, mcopy.cfg.arduino.cmd.mcopy_identifier)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return reject(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
mcopy.arduino.close = async function (callback) {
|
||||
const device = mcopy.arduino.alias['connect']
|
||||
let closeSuccess
|
||||
try {
|
||||
closeSuccess = await close(device)
|
||||
} catch (e) {
|
||||
return console.error(e)
|
||||
}
|
||||
return closeSuccess
|
||||
};
|
||||
|
||||
mcopy.arduino.fakeConnect = async function (serial) {
|
||||
//console.log('Connecting to fake arduino...');
|
||||
const device = '/dev/fake'
|
||||
mcopy.arduino.alias[serial] = device
|
||||
mcopy.arduino.serial[device] = {
|
||||
write : function (cmd, cb) {
|
||||
const t = {
|
||||
c : mcopy.cfg.arduino.cam.time + mcopy.cfg.arduino.cam.delay,
|
||||
p : mcopy.cfg.arduino.proj.time + mcopy.cfg.arduino.proj.delay
|
||||
}
|
||||
let timeout = t[cmd]
|
||||
let end
|
||||
if (typeof timeout === 'undefined') timeout = 10
|
||||
mcopy.arduino.timer = +new Date()
|
||||
setTimeout(() => {
|
||||
mcopy.arduino.end(cmd)
|
||||
return cb()
|
||||
}, timeout)
|
||||
|
||||
},
|
||||
string : async function (str) {
|
||||
//do nothing
|
||||
return true
|
||||
},
|
||||
fake : true
|
||||
};
|
||||
//console.log('Connected to fake arduino! Not real! Doesn\'t exist!');
|
||||
return true
|
||||
}
|
||||
|
||||
if (typeof module !== 'undefined' && module.parent) {
|
||||
module.exports = function (cfg, ee) {
|
||||
eventEmitter = ee
|
||||
mcopy.cfg = cfg
|
||||
return mcopy.arduino
|
||||
}
|
||||
}
|
||||
exports.Arduino = Arduino;
|
||||
module.exports = { Arduino };
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "arduino",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<a name="module_lib/cam"></a>
|
||||
|
||||
## lib/cam
|
||||
|
||||
* [lib/cam](#module_lib/cam)
|
||||
* [~Camera](#module_lib/cam..Camera)
|
||||
* [.init()](#module_lib/cam..Camera+init)
|
||||
* [.listen()](#module_lib/cam..Camera+listen)
|
||||
* [.set()](#module_lib/cam..Camera+set)
|
||||
* [.cap()](#module_lib/cam..Camera+cap)
|
||||
* [.move()](#module_lib/cam..Camera+move)
|
||||
* [.exposure()](#module_lib/cam..Camera+exposure)
|
||||
* [.connectIntval()](#module_lib/cam..Camera+connectIntval)
|
||||
* [.connectProcessing()](#module_lib/cam..Camera+connectProcessing)
|
||||
* [.listener()](#module_lib/cam..Camera+listener)
|
||||
* [.end()](#module_lib/cam..Camera+end)
|
||||
|
||||
<a name="module_lib/cam..Camera"></a>
|
||||
|
||||
### lib/cam~Camera
|
||||
Class representing camera functions.
|
||||
|
||||
**Kind**: inner class of [<code>lib/cam</code>](#module_lib/cam)
|
||||
|
||||
* [~Camera](#module_lib/cam..Camera)
|
||||
* [.init()](#module_lib/cam..Camera+init)
|
||||
* [.listen()](#module_lib/cam..Camera+listen)
|
||||
* [.set()](#module_lib/cam..Camera+set)
|
||||
* [.cap()](#module_lib/cam..Camera+cap)
|
||||
* [.move()](#module_lib/cam..Camera+move)
|
||||
* [.exposure()](#module_lib/cam..Camera+exposure)
|
||||
* [.connectIntval()](#module_lib/cam..Camera+connectIntval)
|
||||
* [.connectProcessing()](#module_lib/cam..Camera+connectProcessing)
|
||||
* [.listener()](#module_lib/cam..Camera+listener)
|
||||
* [.end()](#module_lib/cam..Camera+end)
|
||||
|
||||
<a name="module_lib/cam..Camera+init"></a>
|
||||
|
||||
#### camera.init()
|
||||
**Kind**: instance method of [<code>Camera</code>](#module_lib/cam..Camera)
|
||||
<a name="module_lib/cam..Camera+listen"></a>
|
||||
|
||||
#### camera.listen()
|
||||
**Kind**: instance method of [<code>Camera</code>](#module_lib/cam..Camera)
|
||||
<a name="module_lib/cam..Camera+set"></a>
|
||||
|
||||
#### camera.set()
|
||||
**Kind**: instance method of [<code>Camera</code>](#module_lib/cam..Camera)
|
||||
<a name="module_lib/cam..Camera+cap"></a>
|
||||
|
||||
#### camera.cap()
|
||||
**Kind**: instance method of [<code>Camera</code>](#module_lib/cam..Camera)
|
||||
<a name="module_lib/cam..Camera+move"></a>
|
||||
|
||||
#### camera.move()
|
||||
**Kind**: instance method of [<code>Camera</code>](#module_lib/cam..Camera)
|
||||
<a name="module_lib/cam..Camera+exposure"></a>
|
||||
|
||||
#### camera.exposure()
|
||||
**Kind**: instance method of [<code>Camera</code>](#module_lib/cam..Camera)
|
||||
<a name="module_lib/cam..Camera+connectIntval"></a>
|
||||
|
||||
#### camera.connectIntval()
|
||||
**Kind**: instance method of [<code>Camera</code>](#module_lib/cam..Camera)
|
||||
<a name="module_lib/cam..Camera+connectProcessing"></a>
|
||||
|
||||
#### camera.connectProcessing()
|
||||
**Kind**: instance method of [<code>Camera</code>](#module_lib/cam..Camera)
|
||||
<a name="module_lib/cam..Camera+listener"></a>
|
||||
|
||||
#### camera.listener()
|
||||
**Kind**: instance method of [<code>Camera</code>](#module_lib/cam..Camera)
|
||||
<a name="module_lib/cam..Camera+end"></a>
|
||||
|
||||
#### camera.end()
|
||||
**Kind**: instance method of [<code>Camera</code>](#module_lib/cam..Camera)
|
|
@ -0,0 +1,71 @@
|
|||
import type { Arduino } from 'arduino';
|
||||
import type { FilmOut } from 'filmout';
|
||||
import type { Config } from 'cfg';
|
||||
import type { WebContents } from 'electron';
|
||||
interface CameraState {
|
||||
pos: number;
|
||||
dir: boolean;
|
||||
capper: boolean;
|
||||
}
|
||||
/** @module lib/cam */
|
||||
/**
|
||||
* Class representing camera functions.
|
||||
*/
|
||||
export declare class Camera {
|
||||
state: CameraState;
|
||||
arduino: Arduino;
|
||||
private intval;
|
||||
private processing;
|
||||
private log;
|
||||
private cfg;
|
||||
private filmout;
|
||||
private ui;
|
||||
private ipc;
|
||||
private id;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
constructor(arduino: Arduino, cfg: Config, ui: WebContents, filmout: FilmOut, second?: boolean);
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private init;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private listen;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
set(dir: boolean, id: string): Promise<number>;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
cap(state: boolean, id: string): Promise<number>;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
move(id: string): Promise<number>;
|
||||
both(id: string): Promise<number>;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
exposure(exposure: number, id: string): Promise<number>;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private connectIntval;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private connectProcessing;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private listener;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private end;
|
||||
}
|
||||
export {};
|
|
@ -0,0 +1,346 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Camera = void 0;
|
||||
const electron_1 = require("electron");
|
||||
const intval_1 = require("intval");
|
||||
const processing_1 = require("processing");
|
||||
const delay_1 = require("delay");
|
||||
const log_1 = require("log");
|
||||
/** @module lib/cam */
|
||||
/**
|
||||
* Class representing camera functions.
|
||||
*/
|
||||
class Camera {
|
||||
/**
|
||||
*
|
||||
**/
|
||||
constructor(arduino, cfg, ui, filmout, second = false) {
|
||||
this.state = {
|
||||
pos: 0,
|
||||
dir: true,
|
||||
capper: false
|
||||
};
|
||||
this.arduino = null;
|
||||
this.intval = null;
|
||||
this.processing = null;
|
||||
this.ipc = electron_1.ipcMain;
|
||||
this.id = 'camera';
|
||||
this.arduino = arduino;
|
||||
this.cfg = cfg;
|
||||
this.ui = ui;
|
||||
this.filmout = filmout;
|
||||
if (second)
|
||||
this.id += '_second';
|
||||
this.init();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async init() {
|
||||
this.log = await (0, log_1.Log)({ label: this.id });
|
||||
this.listen();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
listen() {
|
||||
this.ipc.on(this.id, this.listener.bind(this));
|
||||
this.ipc.on('intval', this.connectIntval.bind(this));
|
||||
this.ipc.on('processing', this.connectProcessing.bind(this));
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async set(dir, id) {
|
||||
let cmd;
|
||||
let ms;
|
||||
if (dir) {
|
||||
cmd = this.cfg.arduino.cmd[`${this.id}_forward`];
|
||||
}
|
||||
else {
|
||||
cmd = this.cfg.arduino.cmd[`${this.id}_backward`];
|
||||
}
|
||||
this.state.dir = dir;
|
||||
if (this.processing) {
|
||||
try {
|
||||
ms = await this.processing.setDir(dir);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
else if (this.intval) {
|
||||
try {
|
||||
ms = await this.intval.setDir(dir);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
ms = await this.arduino.send(this.id, cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
return await this.end(cmd, id, ms);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async cap(state, id) {
|
||||
let cmd;
|
||||
let ms;
|
||||
if (state) {
|
||||
cmd = this.cfg.arduino.cmd[`${this.id}_forward`];
|
||||
}
|
||||
else {
|
||||
cmd = this.cfg.arduino.cmd[`${this.id}_backward`];
|
||||
}
|
||||
this.state.capper = state;
|
||||
try {
|
||||
ms = await this.arduino.send(this.id, cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
return await this.end(cmd, id, ms);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async move(id) {
|
||||
const cmd = this.cfg.arduino.cmd[this.id];
|
||||
let ms;
|
||||
if (this.filmout.state.enabled) {
|
||||
await this.filmout.start();
|
||||
}
|
||||
if (this.processing) {
|
||||
try {
|
||||
ms = await this.processing.move();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
else if (this.intval) {
|
||||
try {
|
||||
ms = await this.intval.move();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(`Error moving intval ${this.id}: ${id}`, err);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
ms = await this.arduino.send(this.id, cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
if (this.filmout.state.enabled) {
|
||||
//await delay(100 * 1000);
|
||||
await this.filmout.end();
|
||||
}
|
||||
//this.log.info('Camera move time', { ms });
|
||||
return this.end(cmd, id, ms);
|
||||
}
|
||||
async both(id) {
|
||||
const cmd = this.cfg.arduino.cmd[id];
|
||||
let ms;
|
||||
try {
|
||||
ms = await this.arduino.send(this.id, cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(`Error moving both ${this.id}: ${id}`, err);
|
||||
}
|
||||
//this.log.info('Cameras move time', { ms });
|
||||
return await this.end(cmd, id, ms);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async exposure(exposure, id) {
|
||||
const cmd = this.cfg.arduino.cmd.camera_exposure;
|
||||
const str = `${exposure}`;
|
||||
const started = +new Date();
|
||||
let ms;
|
||||
let confirmState;
|
||||
let parts;
|
||||
let confirmExposure;
|
||||
if (this.intval) {
|
||||
return this.intval.setExposure(exposure, (ms) => {
|
||||
this.ui.send('timing', { c: 'c', ms: exposure });
|
||||
return this.end(cmd, id, ms);
|
||||
});
|
||||
}
|
||||
else if (this.arduino.hasState[this.id]) {
|
||||
try {
|
||||
ms = this.arduino.send(this.id, cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error sending camera exposure command', err);
|
||||
}
|
||||
await (0, delay_1.delay)(1);
|
||||
try {
|
||||
ms = await this.arduino.sendString(this.id, str);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error sending camera exposure string', err);
|
||||
}
|
||||
await ms;
|
||||
await (0, delay_1.delay)(1);
|
||||
try {
|
||||
confirmState = await this.arduino.state(this.id, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(`Error confirming set state`, err);
|
||||
}
|
||||
parts = this.arduino.stateStr[this.id].split('G');
|
||||
if (parts.length > 1) {
|
||||
parts = parts[1].split('H');
|
||||
confirmExposure = parseInt(parts[0]);
|
||||
if (!isNaN(confirmExposure)) {
|
||||
this.log.info(`Exposure successfully set to ${confirmExposure}ms`);
|
||||
this.ui.send('timing', { c: 'c', ms: exposure });
|
||||
}
|
||||
}
|
||||
ms = (+new Date()) - started;
|
||||
return await this.end(cmd, id, ms);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async connectIntval(event, arg) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (arg.connect) {
|
||||
this.intval = new intval_1.Intval(arg.url);
|
||||
this.processing = null;
|
||||
this.intval.connect((err, ms, state) => {
|
||||
if (err) {
|
||||
this.ui.send('intval', { connected: false });
|
||||
this.log.info(`Cannot connect to ${arg.url}`, 'INTVAL');
|
||||
this.intval = null;
|
||||
}
|
||||
else {
|
||||
this.ui.send('intval', { connected: true, url: arg.url, state: state });
|
||||
this.log.info(`Connected to INTVAL3 @ ${arg.url}`, 'INTVAL');
|
||||
}
|
||||
return resolve(true);
|
||||
});
|
||||
}
|
||||
else if (arg.disconnect) {
|
||||
this.intval = null;
|
||||
return resolve(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async connectProcessing(event, arg) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.processing = new processing_1.Processing(arg.url);
|
||||
this.intval = null;
|
||||
this.ui.send('processing', { connected: true, url: arg.url });
|
||||
return resolve(true);
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async listener(event, arg) {
|
||||
if (typeof arg.dir !== 'undefined') {
|
||||
try {
|
||||
await this.set(arg.dir, arg.id);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
else if (typeof arg.move !== 'undefined') {
|
||||
try {
|
||||
await this.move(arg.id);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
else if (typeof arg.val !== 'undefined') {
|
||||
this.state.pos = arg.val;
|
||||
}
|
||||
else if (typeof arg.capper !== 'undefined') {
|
||||
try {
|
||||
await this.cap(arg.capper, arg.id);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
else if (typeof arg.exposure !== 'undefined') {
|
||||
try {
|
||||
await this.exposure(arg.exposure, arg.id);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
event.returnValue = true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async end(cmd, id, ms) {
|
||||
let message = '';
|
||||
if (cmd === this.cfg.arduino.cmd.camera_forward) {
|
||||
message = 'Camera set to FORWARD';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.camera_backward) {
|
||||
message = 'Camera set to BACKWARD';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.camera_second_forward) {
|
||||
message = 'Camera second set to FORWARD';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.camera_second_backward) {
|
||||
message = 'Camera second set to BACKWARD';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.camera) {
|
||||
message = 'Camera ';
|
||||
if (this.state.dir) {
|
||||
message += 'ADVANCED';
|
||||
}
|
||||
else {
|
||||
message += 'REWOUND';
|
||||
}
|
||||
message += ' 1 frame';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.camera_second) {
|
||||
message = 'Camera second ';
|
||||
if (this.state.dir) {
|
||||
message += 'ADVANCED';
|
||||
}
|
||||
else {
|
||||
message += 'REWOUND';
|
||||
}
|
||||
message += ' 1 frame';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.camerass) {
|
||||
message += 'Cameras both MOVED 1 frame each';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.camera_exposure) {
|
||||
message += 'Camera set exposure';
|
||||
}
|
||||
message += ` ${ms}ms`;
|
||||
this.log.info(message);
|
||||
await this.ui.send(this.id, { cmd: cmd, id: id, ms: ms });
|
||||
return ms;
|
||||
}
|
||||
}
|
||||
exports.Camera = Camera;
|
||||
module.exports = { Camera };
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "cam",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<a name="module_lib/capper"></a>
|
||||
|
||||
## lib/capper
|
||||
|
||||
* [lib/capper](#module_lib/capper)
|
||||
* [~Capper](#module_lib/capper..Capper)
|
||||
* [.init()](#module_lib/capper..Capper+init)
|
||||
* [.listen()](#module_lib/capper..Capper+listen)
|
||||
* [.capper()](#module_lib/capper..Capper+capper)
|
||||
* [.listener()](#module_lib/capper..Capper+listener)
|
||||
* [.end()](#module_lib/capper..Capper+end)
|
||||
|
||||
<a name="module_lib/capper..Capper"></a>
|
||||
|
||||
### lib/capper~Capper
|
||||
Class representing capper functions.
|
||||
|
||||
**Kind**: inner class of [<code>lib/capper</code>](#module_lib/capper)
|
||||
|
||||
* [~Capper](#module_lib/capper..Capper)
|
||||
* [.init()](#module_lib/capper..Capper+init)
|
||||
* [.listen()](#module_lib/capper..Capper+listen)
|
||||
* [.capper()](#module_lib/capper..Capper+capper)
|
||||
* [.listener()](#module_lib/capper..Capper+listener)
|
||||
* [.end()](#module_lib/capper..Capper+end)
|
||||
|
||||
<a name="module_lib/capper..Capper+init"></a>
|
||||
|
||||
#### capper.init()
|
||||
**Kind**: instance method of [<code>Capper</code>](#module_lib/capper..Capper)
|
||||
<a name="module_lib/capper..Capper+listen"></a>
|
||||
|
||||
#### capper.listen()
|
||||
**Kind**: instance method of [<code>Capper</code>](#module_lib/capper..Capper)
|
||||
<a name="module_lib/capper..Capper+capper"></a>
|
||||
|
||||
#### capper.capper()
|
||||
**Kind**: instance method of [<code>Capper</code>](#module_lib/capper..Capper)
|
||||
<a name="module_lib/capper..Capper+listener"></a>
|
||||
|
||||
#### capper.listener()
|
||||
**Kind**: instance method of [<code>Capper</code>](#module_lib/capper..Capper)
|
||||
<a name="module_lib/capper..Capper+end"></a>
|
||||
|
||||
#### capper.end()
|
||||
**Kind**: instance method of [<code>Capper</code>](#module_lib/capper..Capper)
|
|
@ -0,0 +1,45 @@
|
|||
import type { FilmOut } from 'filmout';
|
||||
import type { Arduino } from 'arduino';
|
||||
import type { WebContents } from 'electron';
|
||||
interface CapperState {
|
||||
capper: boolean;
|
||||
}
|
||||
/** @module lib/capper */
|
||||
/**
|
||||
* Class representing capper functions.
|
||||
*/
|
||||
export declare class Capper {
|
||||
private state;
|
||||
private arduino;
|
||||
private log;
|
||||
private cfg;
|
||||
private filmout;
|
||||
private ui;
|
||||
private ipc;
|
||||
private id;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
constructor(arduino: Arduino, cfg: any, ui: WebContents, filmout: FilmOut);
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private init;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private listen;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
capper(state: boolean, id: string): Promise<number>;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private listener;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private end;
|
||||
}
|
||||
export type { CapperState };
|
|
@ -0,0 +1,94 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Capper = void 0;
|
||||
const electron_1 = require("electron");
|
||||
const log_1 = require("log");
|
||||
/** @module lib/capper */
|
||||
/**
|
||||
* Class representing capper functions.
|
||||
*/
|
||||
class Capper {
|
||||
/**
|
||||
*
|
||||
**/
|
||||
constructor(arduino, cfg, ui, filmout) {
|
||||
this.state = {
|
||||
capper: false
|
||||
};
|
||||
this.arduino = null;
|
||||
this.ipc = electron_1.ipcMain;
|
||||
this.id = 'capper';
|
||||
this.arduino = arduino;
|
||||
this.cfg = cfg;
|
||||
this.ui = ui;
|
||||
this.filmout = filmout;
|
||||
this.init();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async init() {
|
||||
this.log = await (0, log_1.Log)({ label: this.id });
|
||||
this.listen();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
listen() {
|
||||
this.ipc.on(this.id, this.listener.bind(this));
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async capper(state, id) {
|
||||
let cmd;
|
||||
let ms;
|
||||
if (state) {
|
||||
cmd = this.cfg.arduino.cmd[`${this.id}_on`];
|
||||
}
|
||||
else {
|
||||
cmd = this.cfg.arduino.cmd[`${this.id}_off`];
|
||||
}
|
||||
this.state.capper = state;
|
||||
try {
|
||||
ms = await this.arduino.send(this.id, cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
return await this.end(cmd, id, ms);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async listener(event, arg) {
|
||||
if (typeof arg.state !== 'undefined') {
|
||||
try {
|
||||
await this.capper(arg.state, arg.id);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
event.returnValue = true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async end(cmd, id, ms) {
|
||||
let message = '';
|
||||
if (cmd === this.cfg.arduino.cmd.capper_on) {
|
||||
message = 'Capper set to ON';
|
||||
}
|
||||
else if (cmd === this.cfg.arduino.cmd.capper_off) {
|
||||
message = 'Capper set to OFF';
|
||||
}
|
||||
message += ` ${ms}ms`;
|
||||
this.log.info(message);
|
||||
await this.ui.send(this.id, { cmd: cmd, id: id, ms: ms });
|
||||
return ms;
|
||||
}
|
||||
}
|
||||
exports.Capper = Capper;
|
||||
module.exports = { Capper };
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/capper/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEb,uCAAmC;AAInC,6BAA0B;AAW1B,yBAAyB;AAEzB;;GAEG;AAEH,MAAa,MAAM;IAWlB;;QAEI;IACJ,YAAa,OAAiB,EAAE,GAAS,EAAE,EAAgB,EAAE,OAAiB;QAbtE,UAAK,GAAiB;YAC7B,MAAM,EAAG,KAAK;SACd,CAAC;QACM,YAAO,GAAa,IAAI,CAAC;QAKzB,QAAG,GAAoB,kBAAO,CAAC;QAC/B,OAAE,GAAY,QAAQ,CAAC;QAK9B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;IAED;;QAEI;IACI,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,GAAG,GAAG,MAAM,IAAA,SAAG,EAAC,EAAE,KAAK,EAAG,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;IACf,CAAC;IAED;;QAEI;IACI,MAAM;QACb,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChD,CAAC;IAED;;QAEI;IACI,KAAK,CAAC,MAAM,CAAE,KAAe,EAAE,EAAW;QACjD,IAAI,GAAY,CAAC;QACjB,IAAI,EAAW,CAAC;QAEhB,IAAI,KAAK,EAAE;YACV,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;SAC5C;aAAM;YACN,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;SAC7C;QAED,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;QAE1B,IAAI;YACH,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;SAC3C;QAAC,OAAO,GAAG,EAAE;YACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;SACpB;QAED,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACpC,CAAC;IAED;;QAEI;IACI,KAAK,CAAC,QAAQ,CAAE,KAAoB,EAAE,GAAS;QACtD,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,WAAW,EAAE;YACrC,IAAI;gBACH,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;aACrC;YAAC,OAAO,GAAG,EAAE;gBACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;aACpB;SACD;QACD,KAAK,CAAC,WAAW,GAAG,IAAI,CAAA;IACzB,CAAC;IAED;;QAEI;IACI,KAAK,CAAC,GAAG,CAAE,GAAY,EAAE,EAAW,EAAE,EAAW;QACxD,IAAI,OAAO,GAAY,EAAE,CAAC;QAE1B,IAAI,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE;YAC3C,OAAO,GAAG,kBAAkB,CAAC;SAC7B;aAAM,IAAI,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE;YACnD,OAAO,GAAG,mBAAmB,CAAC;SAC9B;QAED,OAAO,IAAI,IAAI,EAAE,IAAI,CAAC;QAEtB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,MAAM,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAC,CAAC,CAAC;QACzD,OAAO,EAAE,CAAC;IACX,CAAC;CACD;AA7FD,wBA6FC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,MAAM,EAAE,CAAA"}
|
|
@ -1,221 +1,42 @@
|
|||
var capture = {},
|
||||
eventEmitter,
|
||||
fs = require('fs'),
|
||||
exec = require('child_process').exec;
|
||||
'use strict';
|
||||
|
||||
capture.active = false;
|
||||
capture.store = {
|
||||
events : [],
|
||||
start : 0
|
||||
};
|
||||
const req = require('request');
|
||||
|
||||
capture.start = function (first) {
|
||||
'use strict';
|
||||
//reset storage
|
||||
if (capture.active) {
|
||||
capture.store.events = [];
|
||||
capture.store.start = +new Date();
|
||||
const SerialPort = require('serialport');
|
||||
const Readline = SerialPort.parsers.Readline;
|
||||
const parser = new Readline('');
|
||||
const newlineRe = new RegExp('\n', 'g');
|
||||
const returnRe = new RegExp('\r', 'g');
|
||||
|
||||
const { exec } = require('exec');
|
||||
const { delay } = require('delay');
|
||||
|
||||
let system = {};
|
||||
let INTVAL;
|
||||
|
||||
async function capture_intval () {
|
||||
let framePath = `${INTVAL}/frame`;
|
||||
let res;
|
||||
try{
|
||||
res = await req(framePath);
|
||||
} catch (err) {
|
||||
return exit('Error triggering frame', 8);
|
||||
}
|
||||
};
|
||||
capture.end = function () {
|
||||
'use strict';
|
||||
if (capture.active) {
|
||||
return capture.save();
|
||||
} else {
|
||||
return '';
|
||||
if (res) {
|
||||
console.log(res);
|
||||
}
|
||||
};
|
||||
capture.proj_start = function () {
|
||||
'use strict';
|
||||
var e = {
|
||||
'start' : +new Date()
|
||||
};
|
||||
capture.store.events.push(e);
|
||||
};
|
||||
capture.proj_end = function () {
|
||||
'use strict';
|
||||
var e = {
|
||||
'end' : +new Date()
|
||||
};
|
||||
capture.store.events.push(e);
|
||||
};
|
||||
//out-000001
|
||||
capture.pad = function (frame, len) {
|
||||
'use strict';
|
||||
var pad = '',
|
||||
ch = '0';
|
||||
frame += '';
|
||||
len = len - frame.length;
|
||||
if (len <= 0) return frame;
|
||||
while (true) {
|
||||
if (len & 1) {
|
||||
pad += ch;
|
||||
}
|
||||
len >>= 1;
|
||||
if (len) {
|
||||
ch += ch;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pad + frame;
|
||||
};
|
||||
capture.extract = function (input, output, good, real, neg) {
|
||||
'use strict';
|
||||
var tc = capture.report.timecode(good),
|
||||
frame = capture.pad(real, 6),
|
||||
neg_cmd = ' -vf lutrgb="r=negval:g=negval:b=negval" ',
|
||||
cmd = 'ffmpeg -ss ' + tc + ' -i ' + input + '{{neg_cmd}}-vframes 1 ' + output + 'out-' + frame + '.tif';
|
||||
if (neg) {
|
||||
cmd = cmd.replace('{{neg_cmd}}', neg_cmd);
|
||||
} else {
|
||||
cmd = cmd.replace('{{neg_cmd}}', ' ');
|
||||
}
|
||||
console.log(cmd);
|
||||
exec(cmd, function (err, std) {
|
||||
console.log(err);
|
||||
console.log(std);
|
||||
});
|
||||
};
|
||||
capture.cp = function (input, output, good, real) {
|
||||
'use strict';
|
||||
var still = '';
|
||||
};
|
||||
capture.test = function () {
|
||||
'use strict';
|
||||
var i = -1,
|
||||
len = 10,
|
||||
intval,
|
||||
next = function () {
|
||||
i++
|
||||
if (i === len) {
|
||||
clearInterval(intval);
|
||||
intval = null;
|
||||
//console.dir(capture.store);
|
||||
parse();
|
||||
} else {
|
||||
if (i % 2 === 0) {
|
||||
capture.proj_start();
|
||||
} else {
|
||||
capture.proj_end();
|
||||
}
|
||||
}
|
||||
},
|
||||
parse = function () {
|
||||
capture.report.parse(45, 0);
|
||||
};
|
||||
capture.start();
|
||||
next();
|
||||
intval = setInterval(next, 800);
|
||||
};
|
||||
capture.init = function () {
|
||||
'use strict';
|
||||
eventEmitter.on('arduino_send', function (cmd) {
|
||||
if (capture.active
|
||||
&& cmd.trim() === 'p') {
|
||||
capture.proj_start();
|
||||
}
|
||||
});
|
||||
eventEmitter.on('arduino_end', function (cmd) {
|
||||
if (capture.active
|
||||
&& cmd.trim() === 'p') {
|
||||
capture.proj_end();
|
||||
}
|
||||
});
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
capture.save = function () {
|
||||
'use strict';
|
||||
var file = './data/transfer-',
|
||||
time = +new Date(),
|
||||
json = JSON.stringify(capture.store);
|
||||
fs.writeFileSync(file + time + '.json', json, 'utf8');
|
||||
return file + time + '.json';
|
||||
};
|
||||
async function capture_serial () {
|
||||
|
||||
//ffmpeg -f image2 -framerate 24 -start_number 090000 -i input_file_%06d.ext -c:v v210 -an output_file
|
||||
//'-%06d
|
||||
}
|
||||
|
||||
capture.report = {};
|
||||
capture.report.parse = function (inmark, first, report, fps) {
|
||||
'use strict';
|
||||
var all = [],
|
||||
output = {
|
||||
good : [],
|
||||
real : []
|
||||
},
|
||||
good = [],
|
||||
real,
|
||||
f,
|
||||
frame,
|
||||
last = -1,
|
||||
i;
|
||||
if (typeof fps === 'undefined') {
|
||||
fps = 24;
|
||||
}
|
||||
f = 1000 / fps;
|
||||
if (typeof report === 'undefined') {
|
||||
report = capture.store;
|
||||
}
|
||||
if (typeof first === 'undefined') {
|
||||
first = 0;
|
||||
}
|
||||
if (typeof inmark === 'undefined') {
|
||||
inmark = 0;
|
||||
}
|
||||
//first clean frame
|
||||
for (i = 0; i < report.events.length; i++) {
|
||||
if (typeof report.events[i].end !== 'undefined') {
|
||||
frame = (report.events[i].end - report.start) / f;
|
||||
frame = Math.round(frame);
|
||||
last = frame;
|
||||
} else if (typeof report.events[i].start !== 'undefined') {
|
||||
frame = (report.events[i].start - report.start) / f;
|
||||
frame = Math.round(frame);
|
||||
if (last !== -1) {
|
||||
//console.log(last + '-' + frame);
|
||||
all.push(capture.report.arr(last, frame));
|
||||
}
|
||||
}
|
||||
}
|
||||
good = all.map(function (arr) {
|
||||
var center = Math.round(arr.length / 2);
|
||||
return arr[center] + inmark;
|
||||
});
|
||||
async function capture () {
|
||||
|
||||
}
|
||||
|
||||
real = output.map(function (val, i) {
|
||||
return first + i;
|
||||
});
|
||||
|
||||
output.good = good;
|
||||
output.real = real;
|
||||
|
||||
return output;
|
||||
};
|
||||
capture.report.arr = function (start, end) {
|
||||
'use strict';
|
||||
var arr = [],
|
||||
i;
|
||||
for (i = start; i < end + 1; i++) {
|
||||
arr.push(i);
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
capture.report.timecode = function (frame) {
|
||||
'use strict';
|
||||
//00:03:00 no dropframe
|
||||
var a = capture.pad(Math.floor((frame / 60) / 60), 2),
|
||||
b = capture.pad(Math.floor(frame / 60), 2),
|
||||
c = capture.pad(frame % 24);
|
||||
return a + ':' + b + ':' + c;
|
||||
};
|
||||
capture.report.render = function () {
|
||||
'use strict';
|
||||
|
||||
};
|
||||
|
||||
module.exports = function (ee) {
|
||||
eventEmitter = ee;
|
||||
module.exports = (sys) => {
|
||||
system = sys;
|
||||
return capture;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "capture",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
interface ConfigCommands {
|
||||
[key: string]: string;
|
||||
}
|
||||
interface ConfigDeviceProfile {
|
||||
time: number;
|
||||
delay: number;
|
||||
momentary: number;
|
||||
}
|
||||
interface ConfigBlackProfile {
|
||||
before: number;
|
||||
after: number;
|
||||
}
|
||||
interface ConfigProfile {
|
||||
label: string;
|
||||
cam: ConfigDeviceProfile;
|
||||
proj?: ConfigDeviceProfile;
|
||||
black?: ConfigBlackProfile;
|
||||
light: boolean;
|
||||
}
|
||||
interface ConfigProfiles {
|
||||
[key: string]: ConfigProfile;
|
||||
}
|
||||
interface Config {
|
||||
version: string;
|
||||
ext_port: number;
|
||||
profiles: ConfigProfiles;
|
||||
cmd: ConfigCommands;
|
||||
arduino: any;
|
||||
}
|
||||
export type { Config };
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cfg/index.ts"],"names":[],"mappings":""}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,267 @@
|
|||
<a name="module_lib/cmd"></a>
|
||||
|
||||
## lib/cmd
|
||||
|
||||
* [lib/cmd](#module_lib/cmd)
|
||||
* [~Assign all connected devices and mock devices as private classes.](#module_lib/cmd..Assign all connected devices and mock devices as private classes.)
|
||||
* [new Assign all connected devices and mock devices as private classes.(cfg, proj, cam, light, alert, cam2, proj2, capper)](#new_module_lib/cmd..Assign all connected devices and mock devices as private classes._new)
|
||||
* [~Commands](#module_lib/cmd..Commands)
|
||||
* [.projector_forward()](#module_lib/cmd..Commands+projector_forward) ⇒ <code>integer</code>
|
||||
* [.projector_backward()](#module_lib/cmd..Commands+projector_backward) ⇒ <code>integer</code>
|
||||
* [.camera_forward(cmd)](#module_lib/cmd..Commands+camera_forward) ⇒ <code>integer</code>
|
||||
* [.black_forward()](#module_lib/cmd..Commands+black_forward) ⇒ <code>integer</code>
|
||||
* [.camera_backward(cmd)](#module_lib/cmd..Commands+camera_backward) ⇒ <code>integer</code>
|
||||
* [.black_backward()](#module_lib/cmd..Commands+black_backward) ⇒ <code>integer</code>
|
||||
* [.camera_second_forward(cmd)](#module_lib/cmd..Commands+camera_second_forward) ⇒ <code>integer</code>
|
||||
* [.camera_second_backward(cmd)](#module_lib/cmd..Commands+camera_second_backward) ⇒ <code>integer</code>
|
||||
* [.cameras_forward(cmd)](#module_lib/cmd..Commands+cameras_forward) ⇒ <code>integer</code>
|
||||
* [.cameras_backward(cmd)](#module_lib/cmd..Commands+cameras_backward) ⇒ <code>integer</code>
|
||||
* [.camera_forward_camera_second_backward(cmd)](#module_lib/cmd..Commands+camera_forward_camera_second_backward) ⇒ <code>integer</code>
|
||||
* [.camera_backward_camera_second_forward(cmd)](#module_lib/cmd..Commands+camera_backward_camera_second_forward) ⇒ <code>integer</code>
|
||||
* [.projector_second_forward()](#module_lib/cmd..Commands+projector_second_forward) ⇒ <code>integer</code>
|
||||
* [.projector_second_backward()](#module_lib/cmd..Commands+projector_second_backward) ⇒ <code>integer</code>
|
||||
* [.projectors_forward()](#module_lib/cmd..Commands+projectors_forward) ⇒ <code>integer</code>
|
||||
* [.projectors_backward()](#module_lib/cmd..Commands+projectors_backward) ⇒ <code>integer</code>
|
||||
* [.projector_forward_projector_second_backward()](#module_lib/cmd..Commands+projector_forward_projector_second_backward) ⇒ <code>integer</code>
|
||||
* [.projector_backward_projector_second_forward()](#module_lib/cmd..Commands+projector_backward_projector_second_forward) ⇒ <code>integer</code>
|
||||
* [.alert()](#module_lib/cmd..Commands+alert) ⇒ <code>integer</code>
|
||||
* [.pause()](#module_lib/cmd..Commands+pause) ⇒ <code>integer</code>
|
||||
* [.camera_exposure()](#module_lib/cmd..Commands+camera_exposure)
|
||||
|
||||
<a name="module_lib/cmd..Assign all connected devices and mock devices as private classes."></a>
|
||||
|
||||
### lib/cmd~Assign all connected devices and mock devices as private classes.
|
||||
**Kind**: inner class of [<code>lib/cmd</code>](#module_lib/cmd)
|
||||
<a name="new_module_lib/cmd..Assign all connected devices and mock devices as private classes._new"></a>
|
||||
|
||||
#### new Assign all connected devices and mock devices as private classes.(cfg, proj, cam, light, alert, cam2, proj2, capper)
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| cfg | <code>object</code> | Configuration object |
|
||||
| proj | <code>object</code> | Projector 1 |
|
||||
| cam | <code>object</code> | Camera 1 |
|
||||
| light | <code>object</code> | Light source |
|
||||
| alert | <code>object</code> | Alert object |
|
||||
| cam2 | <code>object</code> | (optional) Camera 2 |
|
||||
| proj2 | <code>object</code> | (optional) Projector 2 |
|
||||
| capper | <code>object</code> | Capper object |
|
||||
|
||||
<a name="module_lib/cmd..Commands"></a>
|
||||
|
||||
### lib/cmd~Commands
|
||||
Class representing all commands bundled into methods.
|
||||
|
||||
**Kind**: inner class of [<code>lib/cmd</code>](#module_lib/cmd)
|
||||
|
||||
* [~Commands](#module_lib/cmd..Commands)
|
||||
* [.projector_forward()](#module_lib/cmd..Commands+projector_forward) ⇒ <code>integer</code>
|
||||
* [.projector_backward()](#module_lib/cmd..Commands+projector_backward) ⇒ <code>integer</code>
|
||||
* [.camera_forward(cmd)](#module_lib/cmd..Commands+camera_forward) ⇒ <code>integer</code>
|
||||
* [.black_forward()](#module_lib/cmd..Commands+black_forward) ⇒ <code>integer</code>
|
||||
* [.camera_backward(cmd)](#module_lib/cmd..Commands+camera_backward) ⇒ <code>integer</code>
|
||||
* [.black_backward()](#module_lib/cmd..Commands+black_backward) ⇒ <code>integer</code>
|
||||
* [.camera_second_forward(cmd)](#module_lib/cmd..Commands+camera_second_forward) ⇒ <code>integer</code>
|
||||
* [.camera_second_backward(cmd)](#module_lib/cmd..Commands+camera_second_backward) ⇒ <code>integer</code>
|
||||
* [.cameras_forward(cmd)](#module_lib/cmd..Commands+cameras_forward) ⇒ <code>integer</code>
|
||||
* [.cameras_backward(cmd)](#module_lib/cmd..Commands+cameras_backward) ⇒ <code>integer</code>
|
||||
* [.camera_forward_camera_second_backward(cmd)](#module_lib/cmd..Commands+camera_forward_camera_second_backward) ⇒ <code>integer</code>
|
||||
* [.camera_backward_camera_second_forward(cmd)](#module_lib/cmd..Commands+camera_backward_camera_second_forward) ⇒ <code>integer</code>
|
||||
* [.projector_second_forward()](#module_lib/cmd..Commands+projector_second_forward) ⇒ <code>integer</code>
|
||||
* [.projector_second_backward()](#module_lib/cmd..Commands+projector_second_backward) ⇒ <code>integer</code>
|
||||
* [.projectors_forward()](#module_lib/cmd..Commands+projectors_forward) ⇒ <code>integer</code>
|
||||
* [.projectors_backward()](#module_lib/cmd..Commands+projectors_backward) ⇒ <code>integer</code>
|
||||
* [.projector_forward_projector_second_backward()](#module_lib/cmd..Commands+projector_forward_projector_second_backward) ⇒ <code>integer</code>
|
||||
* [.projector_backward_projector_second_forward()](#module_lib/cmd..Commands+projector_backward_projector_second_forward) ⇒ <code>integer</code>
|
||||
* [.alert()](#module_lib/cmd..Commands+alert) ⇒ <code>integer</code>
|
||||
* [.pause()](#module_lib/cmd..Commands+pause) ⇒ <code>integer</code>
|
||||
* [.camera_exposure()](#module_lib/cmd..Commands+camera_exposure)
|
||||
|
||||
<a name="module_lib/cmd..Commands+projector_forward"></a>
|
||||
|
||||
#### commands.projector\_forward() ⇒ <code>integer</code>
|
||||
Move the projector one frame forward
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
<a name="module_lib/cmd..Commands+projector_backward"></a>
|
||||
|
||||
#### commands.projector\_backward() ⇒ <code>integer</code>
|
||||
Move the projector one frame backward
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
<a name="module_lib/cmd..Commands+camera_forward"></a>
|
||||
|
||||
#### commands.camera\_forward(cmd) ⇒ <code>integer</code>
|
||||
Move the camera one frame forward
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| cmd | <code>object</code> | Full cmd object |
|
||||
|
||||
<a name="module_lib/cmd..Commands+black_forward"></a>
|
||||
|
||||
#### commands.black\_forward() ⇒ <code>integer</code>
|
||||
Move the camera one frame forward with light off
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
<a name="module_lib/cmd..Commands+camera_backward"></a>
|
||||
|
||||
#### commands.camera\_backward(cmd) ⇒ <code>integer</code>
|
||||
Move the camera one frame backward
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| cmd | <code>object</code> | Full cmd object |
|
||||
|
||||
<a name="module_lib/cmd..Commands+black_backward"></a>
|
||||
|
||||
#### commands.black\_backward() ⇒ <code>integer</code>
|
||||
Move the camera one frame forward, light set to black or off
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
<a name="module_lib/cmd..Commands+camera_second_forward"></a>
|
||||
|
||||
#### commands.camera\_second\_forward(cmd) ⇒ <code>integer</code>
|
||||
Move the second camera one frame forward
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| cmd | <code>object</code> | Full cmd object |
|
||||
|
||||
<a name="module_lib/cmd..Commands+camera_second_backward"></a>
|
||||
|
||||
#### commands.camera\_second\_backward(cmd) ⇒ <code>integer</code>
|
||||
Move the second camera one frame backward
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| cmd | <code>object</code> | Full cmd object |
|
||||
|
||||
<a name="module_lib/cmd..Commands+cameras_forward"></a>
|
||||
|
||||
#### commands.cameras\_forward(cmd) ⇒ <code>integer</code>
|
||||
Move the both cameras one frame forward
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| cmd | <code>object</code> | Full cmd object |
|
||||
|
||||
<a name="module_lib/cmd..Commands+cameras_backward"></a>
|
||||
|
||||
#### commands.cameras\_backward(cmd) ⇒ <code>integer</code>
|
||||
Move the both cameras one frame backward
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| cmd | <code>object</code> | Full cmd object |
|
||||
|
||||
<a name="module_lib/cmd..Commands+camera_forward_camera_second_backward"></a>
|
||||
|
||||
#### commands.camera\_forward\_camera\_second\_backward(cmd) ⇒ <code>integer</code>
|
||||
Move first camera one frame forward and rewind secondary camera one frame backward
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| cmd | <code>object</code> | Full cmd object |
|
||||
|
||||
<a name="module_lib/cmd..Commands+camera_backward_camera_second_forward"></a>
|
||||
|
||||
#### commands.camera\_backward\_camera\_second\_forward(cmd) ⇒ <code>integer</code>
|
||||
Rewind first camera one frame backward and move secondary camera one frame forward
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| cmd | <code>object</code> | Full cmd object |
|
||||
|
||||
<a name="module_lib/cmd..Commands+projector_second_forward"></a>
|
||||
|
||||
#### commands.projector\_second\_forward() ⇒ <code>integer</code>
|
||||
Move the secondary projector forward one frame
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
<a name="module_lib/cmd..Commands+projector_second_backward"></a>
|
||||
|
||||
#### commands.projector\_second\_backward() ⇒ <code>integer</code>
|
||||
Rewind the secondary projector backward one frame
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
<a name="module_lib/cmd..Commands+projectors_forward"></a>
|
||||
|
||||
#### commands.projectors\_forward() ⇒ <code>integer</code>
|
||||
Move the both projectors forward one frame
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
<a name="module_lib/cmd..Commands+projectors_backward"></a>
|
||||
|
||||
#### commands.projectors\_backward() ⇒ <code>integer</code>
|
||||
Rewind both projectors backwards one frame
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
<a name="module_lib/cmd..Commands+projector_forward_projector_second_backward"></a>
|
||||
|
||||
#### commands.projector\_forward\_projector\_second\_backward() ⇒ <code>integer</code>
|
||||
Move the primary projector forward one frame and rewind the secondary projector
|
||||
one frame backwards.
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
<a name="module_lib/cmd..Commands+projector_backward_projector_second_forward"></a>
|
||||
|
||||
#### commands.projector\_backward\_projector\_second\_forward() ⇒ <code>integer</code>
|
||||
Rewind the primary projector backwards one frame and move the secondary
|
||||
projector forward one frame.
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
<a name="module_lib/cmd..Commands+alert"></a>
|
||||
|
||||
#### commands.alert() ⇒ <code>integer</code>
|
||||
Throws an alert to pause a sequence
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
<a name="module_lib/cmd..Commands+pause"></a>
|
||||
|
||||
#### commands.pause() ⇒ <code>integer</code>
|
||||
Pauses a sequence for a length of time
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
||||
**Returns**: <code>integer</code> - Length of action in ms
|
||||
<a name="module_lib/cmd..Commands+camera_exposure"></a>
|
||||
|
||||
#### commands.camera\_exposure()
|
||||
Sets the camera exposure (if supported).
|
||||
|
||||
**Kind**: instance method of [<code>Commands</code>](#module_lib/cmd..Commands)
|
|
@ -0,0 +1,179 @@
|
|||
import type { Projector } from 'proj';
|
||||
import type { Camera } from 'cam';
|
||||
import type { Light } from 'light';
|
||||
import type { Capper } from 'capper';
|
||||
import type { Alert } from 'alert';
|
||||
import type { Config } from 'cfg';
|
||||
/** @module lib/cmd */
|
||||
/**
|
||||
* Class representing all commands bundled into methods.
|
||||
*/
|
||||
export declare class Commands {
|
||||
proj: Projector;
|
||||
cam: Camera;
|
||||
light: Light;
|
||||
cam2: Camera;
|
||||
proj2: Projector;
|
||||
capper: Capper;
|
||||
alertObj: Alert;
|
||||
private cfg;
|
||||
private ipc;
|
||||
/**
|
||||
* @constructor
|
||||
* Assign all connected devices and mock devices as private classes.
|
||||
*
|
||||
* @param {object} cfg Configuration object
|
||||
* @param {object} proj Projector 1
|
||||
* @param {object} cam Camera 1
|
||||
* @param {object} light Light source
|
||||
* @param {object} alert Alert object
|
||||
* @param {object} cam2 (optional) Camera 2
|
||||
* @param {object} proj2 (optional) Projector 2
|
||||
* @param {object} capper Capper object
|
||||
*
|
||||
**/
|
||||
constructor(cfg: Config, proj: Projector, cam: Camera, light: Light, alert: Alert, cam2?: Camera, proj2?: Projector, capper?: Capper);
|
||||
/**
|
||||
* Move the projector one frame forward
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
projector_forward(): Promise<number>;
|
||||
/**
|
||||
* Move the projector one frame backward
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
projector_backward(): Promise<number>;
|
||||
/**
|
||||
* Move the camera one frame forward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
camera_forward(): Promise<number>;
|
||||
/**
|
||||
* Move the camera one frame forward with light off
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
black_forward(): Promise<number>;
|
||||
/**
|
||||
* Move the camera one frame backward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
camera_backward(): Promise<number>;
|
||||
/**
|
||||
* Move the camera one frame forward, light set to black or off
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
black_backward(): Promise<number>;
|
||||
/**
|
||||
* Move the second camera one frame forward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
camera_second_forward(): Promise<number>;
|
||||
/**
|
||||
* Move the second camera one frame backward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
camera_second_backward(): Promise<number>;
|
||||
/**
|
||||
* Move the both cameras one frame forward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
cameras_forward(): Promise<number>;
|
||||
/**
|
||||
* Move the both cameras one frame backward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
cameras_backward(): Promise<number>;
|
||||
/**
|
||||
* Move first camera one frame forward and rewind secondary camera one frame backward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
camera_forward_camera_second_backward(): Promise<number>;
|
||||
/**
|
||||
* Rewind first camera one frame backward and move secondary camera one frame forward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
camera_backward_camera_second_forward(): Promise<number>;
|
||||
/**
|
||||
* Move the secondary projector forward one frame
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
projector_second_forward(): Promise<number>;
|
||||
/**
|
||||
* Rewind the secondary projector backward one frame
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
projector_second_backward(): Promise<number>;
|
||||
/**
|
||||
* Move the both projectors forward one frame
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
projectors_forward(): Promise<number>;
|
||||
/**
|
||||
* Rewind both projectors backwards one frame
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
projectors_backward(): Promise<number>;
|
||||
/**
|
||||
* Move the primary projector forward one frame and rewind the secondary projector
|
||||
* one frame backwards.
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
projector_forward_projector_second_backward(): Promise<number>;
|
||||
/**
|
||||
* Rewind the primary projector backwards one frame and move the secondary
|
||||
* projector forward one frame.
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
projector_backward_projector_second_forward(): Promise<number>;
|
||||
/**
|
||||
* Throws an alert to pause a sequence
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
alert(cmd: any): Promise<number>;
|
||||
/**
|
||||
* Pauses a sequence for a length of time
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
pause(cmd: any): Promise<number>;
|
||||
/**
|
||||
* Sets the camera exposure (if supported).
|
||||
*
|
||||
**/
|
||||
camera_exposure(cmd: any): Promise<number>;
|
||||
}
|
|
@ -0,0 +1,645 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Commands = void 0;
|
||||
const electron_1 = require("electron");
|
||||
const uuid_1 = require("uuid");
|
||||
const delay_1 = require("delay");
|
||||
/** @module lib/cmd */
|
||||
/**
|
||||
* Class representing all commands bundled into methods.
|
||||
*/
|
||||
class Commands {
|
||||
/**
|
||||
* @constructor
|
||||
* Assign all connected devices and mock devices as private classes.
|
||||
*
|
||||
* @param {object} cfg Configuration object
|
||||
* @param {object} proj Projector 1
|
||||
* @param {object} cam Camera 1
|
||||
* @param {object} light Light source
|
||||
* @param {object} alert Alert object
|
||||
* @param {object} cam2 (optional) Camera 2
|
||||
* @param {object} proj2 (optional) Projector 2
|
||||
* @param {object} capper Capper object
|
||||
*
|
||||
**/
|
||||
constructor(cfg, proj, cam, light, alert, cam2 = null, proj2 = null, capper = null) {
|
||||
this.ipc = electron_1.ipcMain;
|
||||
this.cfg = cfg;
|
||||
this.proj = proj;
|
||||
this.cam = cam;
|
||||
this.light = light;
|
||||
this.alertObj = alert;
|
||||
if (cam2 !== null)
|
||||
this.cam2 = cam2;
|
||||
if (proj2 !== null)
|
||||
this.proj2 = proj2;
|
||||
if (capper !== null)
|
||||
this.capper = capper;
|
||||
}
|
||||
/**
|
||||
* Move the projector one frame forward
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projector_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
let ms;
|
||||
try {
|
||||
if (!this.proj.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj.set(true, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.proj.move(id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the projector one frame backward
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projector_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
let ms;
|
||||
try {
|
||||
if (this.proj.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj.set(false, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.proj.move(id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the camera one frame forward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async camera_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let ms;
|
||||
try {
|
||||
if (!this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(true, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.cam.move(id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the camera one frame forward with light off
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async black_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let ms = 0;
|
||||
try {
|
||||
if (!this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(true, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.capper) {
|
||||
ms += await this.capper.capper(true, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id); //make sure set to off
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms += await this.cam.move(id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
if (this.capper) {
|
||||
ms += await this.capper.capper(false, id);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the camera one frame backward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async camera_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let ms;
|
||||
try {
|
||||
if (this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(false, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.cam.move(id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the camera one frame forward, light set to black or off
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async black_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let ms = 0;
|
||||
try {
|
||||
if (this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(false, id);
|
||||
}
|
||||
if (this.capper) {
|
||||
ms += await this.capper.capper(true, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id); //make sure set to off
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms += await this.cam.move(id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
if (this.capper) {
|
||||
ms += await this.capper.capper(false, id);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the second camera one frame forward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async camera_second_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let ms;
|
||||
try {
|
||||
if (!this.cam2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam2.set(true, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.cam2.move(id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the second camera one frame backward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async camera_second_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let ms;
|
||||
try {
|
||||
if (this.cam2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam2.set(false, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.cam2.move(id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the both cameras one frame forward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async cameras_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (!this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(true, id);
|
||||
}
|
||||
if (!this.cam2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam2.set(true, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.cam && this.cam2 && this.cam.arduino.alias.camera === this.cam.arduino.alias.camera_second) {
|
||||
ms = await this.cam.both(id);
|
||||
}
|
||||
else {
|
||||
both = await Promise.all([this.cam.move(id), this.cam2.move(id)]);
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the both cameras one frame backward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async cameras_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(false, id);
|
||||
}
|
||||
if (this.cam2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam2.set(false, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.cam && this.cam2 && this.cam.arduino.alias.camera === this.cam.arduino.alias.camera_second) {
|
||||
ms = await this.cam.both(id);
|
||||
}
|
||||
else {
|
||||
both = await Promise.all([this.cam.move(id), this.cam2.move(id)]);
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move first camera one frame forward and rewind secondary camera one frame backward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async camera_forward_camera_second_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (!this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(true, id);
|
||||
}
|
||||
if (this.cam2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam2.set(false, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.cam && this.cam2 && this.cam.arduino.alias.camera === this.cam.arduino.alias.camera_second) {
|
||||
ms = await this.cam.both(id);
|
||||
}
|
||||
else {
|
||||
both = await Promise.all([this.cam.move(id), this.cam2.move(id)]);
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Rewind first camera one frame backward and move secondary camera one frame forward
|
||||
*
|
||||
* @param {object} cmd Full cmd object
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async camera_backward_camera_second_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
const off = [0, 0, 0];
|
||||
let rgb = [255, 255, 255];
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (this.cam.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam.set(false, id);
|
||||
}
|
||||
if (!this.cam2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.cam2.set(true, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(rgb, id);
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.cam && this.cam2 && this.cam.arduino.alias.camera === this.cam.arduino.alias.camera_second) {
|
||||
ms = await this.cam.both(id);
|
||||
}
|
||||
else {
|
||||
both = await Promise.all([this.cam.move(id), this.cam2.move(id)]);
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.light.set(off, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the secondary projector forward one frame
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projector_second_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
let ms;
|
||||
try {
|
||||
if (!this.proj2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj2.set(true, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.proj2.move(id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Rewind the secondary projector backward one frame
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projector_second_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
let ms;
|
||||
try {
|
||||
if (this.proj2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj2.set(false, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
ms = await this.proj2.move(id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the both projectors forward one frame
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projectors_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (!this.proj.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj.set(true, id);
|
||||
}
|
||||
if (!this.proj2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj2.set(true, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.proj && this.proj2 && this.proj.arduino.alias.projector === this.proj.arduino.alias.projector_second) {
|
||||
ms = await this.proj.both(id);
|
||||
}
|
||||
else {
|
||||
both = await Promise.all([this.proj.move(id), this.proj2.move(id)]);
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Rewind both projectors backwards one frame
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projectors_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (this.proj.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj.set(false, id);
|
||||
}
|
||||
if (this.proj2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj2.set(false, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.proj && this.proj2 && this.proj.arduino.alias.projector === this.proj.arduino.alias.projector_second) {
|
||||
ms = await this.proj.both(id);
|
||||
}
|
||||
else {
|
||||
both = await Promise.all([this.proj.move(id), this.proj2.move(id)]);
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Move the primary projector forward one frame and rewind the secondary projector
|
||||
* one frame backwards.
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projector_forward_projector_second_backward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (!this.proj.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj.set(true, id);
|
||||
}
|
||||
if (this.proj2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj2.set(false, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.proj && this.proj2 && this.proj.arduino.alias.projector === this.proj.arduino.alias.projector_second) {
|
||||
ms = await this.proj.both(id);
|
||||
}
|
||||
else {
|
||||
both = await Promise.all([this.proj.move(id), this.proj2.move(id)]);
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Rewind the primary projector backwards one frame and move the secondary
|
||||
* projector forward one frame.
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async projector_backward_projector_second_forward() {
|
||||
const id = (0, uuid_1.v4)();
|
||||
let both;
|
||||
let ms;
|
||||
try {
|
||||
if (this.proj.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj.set(false, id);
|
||||
}
|
||||
if (!this.proj2.state.dir) {
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
await this.proj2.set(true, id);
|
||||
}
|
||||
await (0, delay_1.delay)(this.cfg.arduino.serialDelay);
|
||||
if (this.proj && this.proj2 && this.proj.arduino.alias.projector === this.proj.arduino.alias.projector_second) {
|
||||
ms = await this.proj.both(id);
|
||||
}
|
||||
else {
|
||||
both = await Promise.all([this.proj.move(id), this.proj2.move(id)]);
|
||||
ms = Math.max(...both);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Throws an alert to pause a sequence
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async alert(cmd) {
|
||||
const id = (0, uuid_1.v4)();
|
||||
let ms;
|
||||
try {
|
||||
ms = await this.alertObj.start(cmd.light); //change this meta
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Pauses a sequence for a length of time
|
||||
*
|
||||
* @returns {integer} Length of action in ms
|
||||
**/
|
||||
async pause(cmd) {
|
||||
const id = (0, uuid_1.v4)();
|
||||
let ms;
|
||||
try {
|
||||
ms = await (0, delay_1.delay)(cmd.light * 1000); //delay is in seconds
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
/**
|
||||
* Sets the camera exposure (if supported).
|
||||
*
|
||||
**/
|
||||
async camera_exposure(cmd) {
|
||||
const id = (0, uuid_1.v4)();
|
||||
let ms;
|
||||
try {
|
||||
ms = await this.cam.exposure(cmd.light, id);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
}
|
||||
exports.Commands = Commands;
|
||||
module.exports = { Commands };
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "cmd",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<a name="delay"></a>
|
||||
|
||||
## delay(ms) ⇒ <code>Promise</code>
|
||||
Delay in an async/await function
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>Promise</code> - Promise to resolve after timeout
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| ms | <code>integer</code> | Milliseconds to delay for |
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* Delay in an async/await function
|
||||
*
|
||||
* @param {integer} ms Milliseconds to delay for
|
||||
*
|
||||
* @returns {Promise} Promise to resolve after timeout
|
||||
**/
|
||||
export declare function delay(ms: number): Promise<number>;
|
|
@ -0,0 +1,18 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.delay = void 0;
|
||||
/**
|
||||
* Delay in an async/await function
|
||||
*
|
||||
* @param {integer} ms Milliseconds to delay for
|
||||
*
|
||||
* @returns {Promise} Promise to resolve after timeout
|
||||
**/
|
||||
function delay(ms) {
|
||||
return new Promise((resolve) => {
|
||||
return setTimeout(() => { resolve(ms); }, ms);
|
||||
});
|
||||
}
|
||||
exports.delay = delay;
|
||||
module.exports = { delay };
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/delay/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEb;;;;;;IAMI;AAEJ,SAAgB,KAAK,CAAE,EAAW;IACjC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAa,EAAE,EAAE;QACpC,OAAO,UAAU,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC,CAAA,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACJ,CAAC;AAJD,sBAIC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,CAAC"}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "delay",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
<a name="module_lib/devices"></a>
|
||||
|
||||
## lib/devices
|
||||
|
||||
* [lib/devices](#module_lib/devices)
|
||||
* [~Devices](#module_lib/devices..Devices)
|
||||
* [new Devices()](#new_module_lib/devices..Devices_new)
|
||||
* [.init()](#module_lib/devices..Devices+init)
|
||||
* [.listen()](#module_lib/devices..Devices+listen)
|
||||
* [.listener()](#module_lib/devices..Devices+listener)
|
||||
* [.enumerate()](#module_lib/devices..Devices+enumerate)
|
||||
* [.favor()](#module_lib/devices..Devices+favor)
|
||||
* [.distinguish()](#module_lib/devices..Devices+distinguish)
|
||||
* [.fakeProjector()](#module_lib/devices..Devices+fakeProjector)
|
||||
* [.fakeCamera()](#module_lib/devices..Devices+fakeCamera)
|
||||
* [.fakeLight()](#module_lib/devices..Devices+fakeLight)
|
||||
* [.fakeCapper()](#module_lib/devices..Devices+fakeCapper)
|
||||
* [.connectDevice()](#module_lib/devices..Devices+connectDevice)
|
||||
* [.all()](#module_lib/devices..Devices+all)
|
||||
* [.remember()](#module_lib/devices..Devices+remember)
|
||||
* [.ready()](#module_lib/devices..Devices+ready)
|
||||
|
||||
<a name="module_lib/devices..Devices"></a>
|
||||
|
||||
### lib/devices~Devices
|
||||
Class representing the device discovery features.
|
||||
|
||||
**Kind**: inner class of [<code>lib/devices</code>](#module_lib/devices)
|
||||
|
||||
* [~Devices](#module_lib/devices..Devices)
|
||||
* [new Devices()](#new_module_lib/devices..Devices_new)
|
||||
* [.init()](#module_lib/devices..Devices+init)
|
||||
* [.listen()](#module_lib/devices..Devices+listen)
|
||||
* [.listener()](#module_lib/devices..Devices+listener)
|
||||
* [.enumerate()](#module_lib/devices..Devices+enumerate)
|
||||
* [.favor()](#module_lib/devices..Devices+favor)
|
||||
* [.distinguish()](#module_lib/devices..Devices+distinguish)
|
||||
* [.fakeProjector()](#module_lib/devices..Devices+fakeProjector)
|
||||
* [.fakeCamera()](#module_lib/devices..Devices+fakeCamera)
|
||||
* [.fakeLight()](#module_lib/devices..Devices+fakeLight)
|
||||
* [.fakeCapper()](#module_lib/devices..Devices+fakeCapper)
|
||||
* [.connectDevice()](#module_lib/devices..Devices+connectDevice)
|
||||
* [.all()](#module_lib/devices..Devices+all)
|
||||
* [.remember()](#module_lib/devices..Devices+remember)
|
||||
* [.ready()](#module_lib/devices..Devices+ready)
|
||||
|
||||
<a name="new_module_lib/devices..Devices_new"></a>
|
||||
|
||||
#### new Devices()
|
||||
Constructor assigns arduino, settings, UI browser window and cam objects
|
||||
locally to this class for reference.
|
||||
|
||||
<a name="module_lib/devices..Devices+init"></a>
|
||||
|
||||
#### devices.init()
|
||||
Initialize the log for "devices". Establish an ipc connection to the UI.
|
||||
Start listening on that ipc connection.
|
||||
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
||||
<a name="module_lib/devices..Devices+listen"></a>
|
||||
|
||||
#### devices.listen()
|
||||
Listen to the "profile" channel for messages from the UI.
|
||||
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
||||
<a name="module_lib/devices..Devices+listener"></a>
|
||||
|
||||
#### devices.listener()
|
||||
The "profile" channel callback. If a profile is changed, set it in the
|
||||
local settings object.
|
||||
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
||||
<a name="module_lib/devices..Devices+enumerate"></a>
|
||||
|
||||
#### devices.enumerate()
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
||||
<a name="module_lib/devices..Devices+favor"></a>
|
||||
|
||||
#### devices.favor()
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
||||
<a name="module_lib/devices..Devices+distinguish"></a>
|
||||
|
||||
#### devices.distinguish()
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
||||
<a name="module_lib/devices..Devices+fakeProjector"></a>
|
||||
|
||||
#### devices.fakeProjector()
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
||||
<a name="module_lib/devices..Devices+fakeCamera"></a>
|
||||
|
||||
#### devices.fakeCamera()
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
||||
<a name="module_lib/devices..Devices+fakeLight"></a>
|
||||
|
||||
#### devices.fakeLight()
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
||||
<a name="module_lib/devices..Devices+fakeCapper"></a>
|
||||
|
||||
#### devices.fakeCapper()
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
||||
<a name="module_lib/devices..Devices+connectDevice"></a>
|
||||
|
||||
#### devices.connectDevice()
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
||||
<a name="module_lib/devices..Devices+all"></a>
|
||||
|
||||
#### devices.all()
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
||||
<a name="module_lib/devices..Devices+remember"></a>
|
||||
|
||||
#### devices.remember()
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
||||
<a name="module_lib/devices..Devices+ready"></a>
|
||||
|
||||
#### devices.ready()
|
||||
**Kind**: instance method of [<code>Devices</code>](#module_lib/devices..Devices)
|
|
@ -0,0 +1,84 @@
|
|||
import type { Settings } from 'settings';
|
||||
import type { Arduino } from 'arduino';
|
||||
import type { BrowserWindow } from 'electron';
|
||||
interface Device {
|
||||
serial: string;
|
||||
device: string;
|
||||
}
|
||||
/** @module lib/devices */
|
||||
/**
|
||||
* Class representing the device discovery features.
|
||||
*/
|
||||
export declare class Devices {
|
||||
settings: Settings;
|
||||
connected: any;
|
||||
private arduino;
|
||||
private log;
|
||||
private ui;
|
||||
private ipc;
|
||||
private mainWindow;
|
||||
/**
|
||||
* Constructor assigns arduino, settings, UI browser window and cam objects
|
||||
* locally to this class for reference.
|
||||
**/
|
||||
constructor(arduino: Arduino, settings: Settings, mainWindow: BrowserWindow);
|
||||
/**
|
||||
* Initialize the log for "devices". Establish an ipc connection to the UI.
|
||||
* Start listening on that ipc connection.
|
||||
**/
|
||||
private init;
|
||||
/**
|
||||
* Listen to the "profile" channel for messages from the UI.
|
||||
**/
|
||||
private listen;
|
||||
/**
|
||||
* The "profile" channel callback. If a profile is changed, set it in the
|
||||
* local settings object.
|
||||
**/
|
||||
private listener;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
enumerate(): Promise<boolean>;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private favor;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private distinguish;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private fakeProjector;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private fakeCamera;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private fakeLight;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private fakeCapper;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private connectDevice;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private all;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private remember;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private ready;
|
||||
}
|
||||
export type { Device };
|
|
@ -0,0 +1,584 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Devices = void 0;
|
||||
const electron_1 = require("electron");
|
||||
const delay_1 = require("delay");
|
||||
const log_1 = require("log");
|
||||
/** @module lib/devices */
|
||||
/**
|
||||
* Class representing the device discovery features.
|
||||
*/
|
||||
class Devices {
|
||||
/**
|
||||
* Constructor assigns arduino, settings, UI browser window and cam objects
|
||||
* locally to this class for reference.
|
||||
**/
|
||||
constructor(arduino, settings, mainWindow) {
|
||||
this.connected = {};
|
||||
this.ipc = electron_1.ipcMain;
|
||||
this.arduino = arduino;
|
||||
this.settings = settings;
|
||||
this.mainWindow = mainWindow;
|
||||
this.ui = this.mainWindow.webContents;
|
||||
this.init();
|
||||
}
|
||||
/**
|
||||
* Initialize the log for "devices". Establish an ipc connection to the UI.
|
||||
* Start listening on that ipc connection.
|
||||
**/
|
||||
async init() {
|
||||
this.log = await (0, log_1.Log)({ label: 'devices' });
|
||||
this.listen();
|
||||
}
|
||||
/**
|
||||
* Listen to the "profile" channel for messages from the UI.
|
||||
**/
|
||||
listen() {
|
||||
this.ipc.handle('profile', this.listener.bind(this));
|
||||
}
|
||||
/**
|
||||
* The "profile" channel callback. If a profile is changed, set it in the
|
||||
* local settings object.
|
||||
**/
|
||||
async listener(event, arg) {
|
||||
if (typeof arg.profile !== 'undefined') {
|
||||
this.log.info(`Saving profile ${arg.profile}`, 'SETTINGS', false, false);
|
||||
this.settings.update('profile', arg.profile);
|
||||
await this.settings.save();
|
||||
}
|
||||
if (typeof arg.timing !== 'undefined') {
|
||||
this.log.info(`Saving timing info`, 'SETTINGS', false, false);
|
||||
this.settings.update('timing', arg.timing);
|
||||
await this.settings.save();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async enumerate() {
|
||||
let serials;
|
||||
try {
|
||||
serials = await this.arduino.enumerate();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.warn(err, 'SERIAL', false, true);
|
||||
await (0, delay_1.delay)(1000);
|
||||
return this.all([]);
|
||||
}
|
||||
this.log.info(`Found ${serials.length} USB devices`, 'SERIAL', true, true);
|
||||
serials = this.favor(serials);
|
||||
return await this.all(serials);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
favor(serials) {
|
||||
const past = this.settings.state.devices.filter((device) => {
|
||||
if (device.serial) {
|
||||
return device;
|
||||
}
|
||||
}).map((device) => {
|
||||
return device.serial;
|
||||
});
|
||||
if (past.length === 0) {
|
||||
return serials;
|
||||
}
|
||||
serials.sort((a, b) => {
|
||||
if (past.indexOf(a) !== -1 && past.indexOf(b) === -1) {
|
||||
return 1;
|
||||
}
|
||||
else if (past.indexOf(a) === -1 && past.indexOf(b) !== -1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
return serials;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async distinguish(serial) {
|
||||
let connectSuccess;
|
||||
let verifySuccess;
|
||||
let device;
|
||||
//this.log.info(`distinguish() ${serial}`)
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('connect', serial, true);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting', err);
|
||||
return null;
|
||||
}
|
||||
await (0, delay_1.delay)(2000);
|
||||
try {
|
||||
verifySuccess = await this.arduino.verify();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error verifying device', err);
|
||||
return null;
|
||||
}
|
||||
this.log.info(`Verified ${serial} as mcopy device`, 'SERIAL', true, true);
|
||||
await (0, delay_1.delay)(1000);
|
||||
try {
|
||||
device = await this.arduino.distinguish();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error distinguishing device', err);
|
||||
return null;
|
||||
}
|
||||
this.remember(device, serial, 'arduino');
|
||||
this.log.info(`Determined ${device} to be ${device}`, 'SERIAL', true, true);
|
||||
await (0, delay_1.delay)(100);
|
||||
try {
|
||||
await this.arduino.state(device, true);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error checking state capability', err);
|
||||
}
|
||||
return device;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async fakeProjector() {
|
||||
this.connected.projector = '/dev/fake';
|
||||
try {
|
||||
await this.arduino.fakeConnect('projector');
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(`Error connecting to fake PROjECTOR device`, 'SERIAL', true, true);
|
||||
this.log.error(err);
|
||||
return false;
|
||||
}
|
||||
this.log.info('Connected to fake PROJECTOR device', 'SERIAL', true, true);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async fakeCamera() {
|
||||
this.connected.camera = '/dev/fake';
|
||||
try {
|
||||
await this.arduino.fakeConnect('camera');
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(`Error connecting to fake CAMERA device`, 'SERIAL', true, true);
|
||||
this.log.error(err);
|
||||
return false;
|
||||
}
|
||||
this.log.info('Connected to fake CAMERA device', 'SERIAL', true, true);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async fakeLight() {
|
||||
this.connected.light = '/dev/fake';
|
||||
try {
|
||||
await this.arduino.fakeConnect('light');
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(`Error connecting to fake LIGHT device`, 'SERIAL', true, true);
|
||||
this.log.error(err);
|
||||
return false;
|
||||
}
|
||||
this.log.info('Connected to fake LIGHT device', 'SERIAL', true, true);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async fakeCapper() {
|
||||
this.connected.capper = '/dev/fake';
|
||||
try {
|
||||
await this.arduino.fakeConnect('capper');
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(`Error connecting to fake CAPPER device`, 'SERIAL', true, true);
|
||||
this.log.error(err);
|
||||
return false;
|
||||
}
|
||||
this.log.info('Connected to fake CAPPER device', 'SERIAL', true, true);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async connectDevice(device, serial) {
|
||||
let closeSuccess;
|
||||
let connectSuccess;
|
||||
try {
|
||||
closeSuccess = await this.arduino.close();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error closing arduino connection', err);
|
||||
return false;
|
||||
}
|
||||
if (device === 'projector') {
|
||||
this.connected.projector = serial;
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('projector', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to projector', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as PROJECTOR`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'camera') {
|
||||
this.connected.camera = serial;
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as CAMERA`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'light') {
|
||||
this.connected.light = serial;
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('light', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to light', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as LIGHT`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'projector,light') {
|
||||
this.connected.projector = serial;
|
||||
this.connected.light = serial;
|
||||
this.arduino.aliasSerial('light', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('projector', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to projector and light', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as PROJECTOR + LIGHT`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'projector,camera,light') {
|
||||
this.connected.projector = serial;
|
||||
this.connected.camera = serial;
|
||||
this.connected.light = serial;
|
||||
this.arduino.aliasSerial('camera', serial);
|
||||
this.arduino.aliasSerial('light', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('projector', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to projector, camera and light', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as PROJECTOR + CAMERA + LIGHT`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'projector,camera') {
|
||||
this.connected.projector = serial;
|
||||
this.connected.camera = serial;
|
||||
this.arduino.aliasSerial('camera', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('projector', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to projector and camera', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as PROJECTOR + CAMERA`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'projector_second') {
|
||||
this.connected.projector_second = serial;
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('projector_second', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to secondary projector', err);
|
||||
return false;
|
||||
}
|
||||
this.log.info(`Connected to ${device} as PROJECTOR_SECOND`, 'SERIAL', true, true);
|
||||
}
|
||||
else if (device === 'projector,projector_second') {
|
||||
this.connected.projector = serial;
|
||||
this.connected.projector_second = serial;
|
||||
this.arduino.aliasSerial('projector_second', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('projector', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to projector and secondary projector', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera_second') {
|
||||
this.connected.camera_second = serial;
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera_second', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,camera_second') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.camera_second = serial;
|
||||
this.arduino.aliasSerial('camera_second', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera, camera_secondary and projector', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,projector,projector_second') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.projector = serial;
|
||||
this.connected.projector_second = serial;
|
||||
this.arduino.aliasSerial('projector', serial);
|
||||
this.arduino.aliasSerial('projector_second', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera, projector and projector_second', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,camera_second,projector') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.camera_second = serial;
|
||||
this.connected.projector = serial;
|
||||
this.arduino.aliasSerial('camera_second', serial);
|
||||
this.arduino.aliasSerial('projector', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera, camera_second and projector', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,camera_second,projector,projector_second') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.camera_second = serial;
|
||||
this.connected.projector = serial;
|
||||
this.connected.projector_second = serial;
|
||||
this.arduino.aliasSerial('camera_second', serial);
|
||||
this.arduino.aliasSerial('projector', serial);
|
||||
this.arduino.aliasSerial('projector_second', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera, camera_second, projector and projector_second', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'capper') {
|
||||
this.connected.capper = serial;
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('capper', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting capper', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,capper') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.capper = serial;
|
||||
this.arduino.aliasSerial('capper', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera and capper', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,capper,projector') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.capper = serial;
|
||||
this.connected.projector = serial;
|
||||
this.arduino.aliasSerial('capper', serial);
|
||||
this.arduino.aliasSerial('projector', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera, capper and projector', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device === 'camera,capper,projector,projector_second') {
|
||||
this.connected.camera = serial;
|
||||
this.connected.capper = serial;
|
||||
this.connected.projector = serial;
|
||||
this.connected.projector_second = serial;
|
||||
this.arduino.aliasSerial('capper', serial);
|
||||
this.arduino.aliasSerial('projector', serial);
|
||||
this.arduino.aliasSerial('projector_second', serial);
|
||||
try {
|
||||
connectSuccess = await this.arduino.connect('camera', serial, false);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to camera, capper, projector and projector_second', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return connectSuccess;
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
//Cases for 1 or 2 arduinos connected
|
||||
async all(serials) {
|
||||
let c = {};
|
||||
let p = {};
|
||||
let l = {};
|
||||
let device;
|
||||
let d;
|
||||
let cs = {};
|
||||
let ps = {};
|
||||
let capper = {};
|
||||
let checklist = [];
|
||||
let exposure;
|
||||
let parts;
|
||||
this.connected = {
|
||||
projector: false,
|
||||
camera: false,
|
||||
light: false,
|
||||
projector_second: false,
|
||||
capper: false
|
||||
};
|
||||
for (let serial of serials) {
|
||||
try {
|
||||
device = await this.distinguish(serial);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error distinguishing device', err);
|
||||
throw err;
|
||||
}
|
||||
try {
|
||||
await this.connectDevice(device, serial);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error connecting to device', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
//done checking devices
|
||||
if (!this.connected.projector) {
|
||||
await this.fakeProjector();
|
||||
}
|
||||
else if (this.arduino.hasState['projector']) {
|
||||
p.state = true;
|
||||
}
|
||||
p.arduino = this.connected.projector;
|
||||
if (!this.connected.camera) {
|
||||
await this.fakeCamera();
|
||||
}
|
||||
else if (this.arduino.hasState['camera']) {
|
||||
if (device.indexOf('camera') !== -1) {
|
||||
parts = this.arduino.stateStr[device].split('G');
|
||||
if (parts.length > 1) {
|
||||
parts = parts[1].split('H');
|
||||
exposure = parseInt(parts[0]);
|
||||
if (!isNaN(exposure)) {
|
||||
this.log.info(`Timing for [${device}] = ${exposure}`);
|
||||
this.ui.send('timing', { c: 'c', ms: exposure });
|
||||
}
|
||||
}
|
||||
}
|
||||
c.state = true;
|
||||
c.exposure = true;
|
||||
}
|
||||
c.arduino = this.connected.camera;
|
||||
if (!this.connected.light) {
|
||||
await this.fakeLight();
|
||||
}
|
||||
l.arduino = this.connected.light;
|
||||
if (this.connected.camera_second) {
|
||||
cs.arduino = this.connected.camera_second;
|
||||
}
|
||||
if (this.connected.projector_second) {
|
||||
ps.arduino = this.connected.projector_second;
|
||||
}
|
||||
if (this.connected.capper) {
|
||||
capper.arduino = this.connected.capper;
|
||||
}
|
||||
if (this.settings.state.camera && this.settings.state.camera.intval) {
|
||||
c.intval = this.settings.state.camera.intval;
|
||||
}
|
||||
return this.ready(p, c, l, cs, ps, capper);
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
remember(device, serial, type) {
|
||||
let deviceEntry;
|
||||
const match = this.settings.state.devices.filter((dev) => {
|
||||
if (typeof dev.device !== 'undefined' && dev.device === device &&
|
||||
typeof dev.serial !== 'undefined' && dev.serial === serial) {
|
||||
return dev;
|
||||
}
|
||||
});
|
||||
if (match.length === 0) {
|
||||
deviceEntry = {
|
||||
device,
|
||||
type,
|
||||
serial
|
||||
};
|
||||
this.settings.state.devices.push(deviceEntry);
|
||||
this.settings.update('devices', this.settings.state.devices);
|
||||
this.settings.save();
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
ready(projector, camera, light, camera_second, projector_second, capper) {
|
||||
let args = {
|
||||
camera,
|
||||
projector,
|
||||
light,
|
||||
profile: this.settings.state.profile
|
||||
};
|
||||
if (this.settings.state.timing) {
|
||||
args.timing = this.settings.state.timing;
|
||||
}
|
||||
if (projector_second && projector_second.arduino) {
|
||||
args.projector_second = projector_second;
|
||||
this.settings.update('projector_second', projector_second);
|
||||
this.mainWindow.setSize(800, 800);
|
||||
}
|
||||
if (camera_second && camera_second.arduino) {
|
||||
args.camera_second = camera_second;
|
||||
this.settings.update('camera_second', camera_second);
|
||||
if (projector_second && projector_second.arduino) {
|
||||
this.mainWindow.setSize(900, 800);
|
||||
}
|
||||
else {
|
||||
this.mainWindow.setSize(800, 800);
|
||||
}
|
||||
}
|
||||
if (capper && capper.arduino) {
|
||||
args.capper = capper;
|
||||
this.mainWindow.setSize(800, 800);
|
||||
this.settings.update('capper', capper);
|
||||
}
|
||||
this.settings.update('camera', camera);
|
||||
this.settings.update('projector', projector);
|
||||
this.settings.update('light', light);
|
||||
this.settings.save();
|
||||
this.ui.send('ready', args);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
exports.Devices = Devices;
|
||||
module.exports = { Devices };
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "devices",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<a name="module_lib/display"></a>
|
||||
|
||||
## lib/display
|
||||
<a name="module_lib/display..electron_1"></a>
|
||||
|
||||
### lib/display~electron\_1
|
||||
Provides features for displaying a full screen display of images for the digital module.
|
||||
|
||||
**Kind**: inner constant of [<code>lib/display</code>](#module_lib/display)
|
|
@ -0,0 +1,18 @@
|
|||
import type { System } from 'system';
|
||||
export declare class Display {
|
||||
private platform;
|
||||
private displays;
|
||||
private display;
|
||||
private tmpdir;
|
||||
private wv;
|
||||
constructor(sys: System);
|
||||
open(): Promise<void>;
|
||||
show(src: string): Promise<void>;
|
||||
showPath(pathStr: string): Promise<unknown>;
|
||||
hide(): void;
|
||||
close(): Promise<boolean>;
|
||||
focus(): Promise<boolean>;
|
||||
field(ratio: number): Promise<boolean>;
|
||||
meter(): Promise<boolean>;
|
||||
change(id: string): void;
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Display = void 0;
|
||||
/**
|
||||
* @module lib/display */
|
||||
/**
|
||||
* Provides features for displaying a full screen display of images for the digital module.
|
||||
**/
|
||||
const electron_1 = require("electron");
|
||||
const path_1 = require("path");
|
||||
const url_1 = require("url");
|
||||
const delay_1 = require("delay");
|
||||
const log_1 = require("log");
|
||||
class WebView {
|
||||
constructor(platform, display) {
|
||||
this.opened = false;
|
||||
this.showing = false;
|
||||
this.loadWait = {};
|
||||
this.ipc = electron_1.ipcMain;
|
||||
const prefs = {
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
allowRunningInsecureContent: false,
|
||||
//enableRemoteModule: true,
|
||||
contextIsolation: false
|
||||
},
|
||||
width: 800,
|
||||
height: 600,
|
||||
minWidth: 800,
|
||||
minHeight: 600 //,
|
||||
//icon: path.join(__dirname, '../../assets/icons/icon.png')
|
||||
};
|
||||
const pagePath = (0, path_1.normalize)((0, path_1.join)(__dirname, '../../display.html'));
|
||||
const pageUrl = (0, url_1.format)({
|
||||
pathname: pagePath,
|
||||
protocol: 'file:'
|
||||
});
|
||||
this.init();
|
||||
if (!display.primary) {
|
||||
prefs.x = display.x + 50;
|
||||
prefs.y = display.y + 50;
|
||||
}
|
||||
this.digitalWindow = new electron_1.BrowserWindow(prefs);
|
||||
require('@electron/remote/main').enable(this.digitalWindow.webContents);
|
||||
this.digitalWindow.loadURL(pageUrl);
|
||||
if (process.argv.indexOf('-d') !== -1 || process.argv.indexOf('--dev') !== -1) {
|
||||
this.digitalWindow.webContents.openDevTools();
|
||||
}
|
||||
this.digitalWindow.on('closed', () => {
|
||||
this.digitalWindow = null;
|
||||
this.close();
|
||||
});
|
||||
//this.digitalWindow.hide();
|
||||
this.platform = platform;
|
||||
this.display = display;
|
||||
this.ipc.on('display_load', this.onLoad.bind(this));
|
||||
}
|
||||
async init() {
|
||||
this.log = await (0, log_1.Log)({ label: 'devices' });
|
||||
}
|
||||
async open() {
|
||||
this.digitalWindow.show();
|
||||
this.showing = true;
|
||||
this.opened = true;
|
||||
await this.digitalWindow.setFullScreen(true);
|
||||
await (0, delay_1.delay)(300);
|
||||
if (this.platform === 'osx') {
|
||||
await (0, delay_1.delay)(300); //give macs an extra 300ms to open fullscreen
|
||||
}
|
||||
}
|
||||
async show(src) {
|
||||
const normalSrc = (0, path_1.normalize)((0, path_1.join)(src));
|
||||
if (!this.digitalWindow) {
|
||||
this.log.warn(`Cannot show "${src}" because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
this.digitalWindow.webContents.send('display', { src: normalSrc });
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
this.showing = true;
|
||||
return new Promise(function (resolve) {
|
||||
this.loadWait[src] = resolve;
|
||||
}.bind(this));
|
||||
}
|
||||
onLoad(evt, arg) {
|
||||
if (this.loadWait[arg.src]) {
|
||||
this.loadWait[arg.src]();
|
||||
delete this.loadWait[arg.src];
|
||||
}
|
||||
}
|
||||
async focus() {
|
||||
if (!this.digitalWindow) {
|
||||
this.log.warn(`Cannot show focus screen because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await (0, delay_1.delay)(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('focus', { focus: true });
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
async field(ratio) {
|
||||
if (!this.digitalWindow) {
|
||||
this.log.warn(`Cannot show field guide because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await (0, delay_1.delay)(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('field', { field: true, ratio });
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
async meter() {
|
||||
if (!this.digitalWindow) {
|
||||
this.log.warn(`Cannot show meter screen because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await (0, delay_1.delay)(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('meter', { meter: true });
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
hide() {
|
||||
if (this.digitalWindow) {
|
||||
this.digitalWindow.hide();
|
||||
}
|
||||
this.showing = false;
|
||||
return true;
|
||||
}
|
||||
close() {
|
||||
this.hide();
|
||||
if (this.digitalWindow) {
|
||||
this.digitalWindow.close();
|
||||
this.digitalWindow = null;
|
||||
}
|
||||
this.opened = false;
|
||||
this.showing = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Display {
|
||||
constructor(sys) {
|
||||
this.platform = sys.platform;
|
||||
this.displays = sys.displays;
|
||||
this.tmpdir = (0, path_1.join)(sys.tmp, 'mcopy_digital');
|
||||
this.display = this.displays.find((display) => {
|
||||
if (display.primary)
|
||||
return true;
|
||||
});
|
||||
}
|
||||
async open() {
|
||||
if (this.wv && this.wv.display && this.wv.display.id !== this.display.id) {
|
||||
this.wv.close();
|
||||
}
|
||||
if (!this.wv || !this.wv.opened) {
|
||||
this.wv = new WebView(this.platform, this.display);
|
||||
await this.wv.open();
|
||||
}
|
||||
}
|
||||
async show(src) {
|
||||
await this.wv.show(src);
|
||||
}
|
||||
async showPath(pathStr) {
|
||||
return await this.wv.show(pathStr);
|
||||
}
|
||||
hide() {
|
||||
}
|
||||
async close() {
|
||||
return await this.wv.close();
|
||||
}
|
||||
async focus() {
|
||||
return await this.wv.focus();
|
||||
}
|
||||
async field(ratio) {
|
||||
return await this.wv.field(ratio);
|
||||
}
|
||||
async meter() {
|
||||
return await this.wv.meter();
|
||||
}
|
||||
change(id) {
|
||||
this.display = this.displays.find((display) => {
|
||||
if (display.id == id)
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.Display = Display;
|
||||
module.exports = { Display };
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "display",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<a name="exec"></a>
|
||||
|
||||
## exec(cmd, arg, opts) ⇒ <code>Promise.<{stdout: string, stderr: stderr}></code>
|
||||
Promisified child_process.exec
|
||||
|
||||
**Kind**: global function
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| cmd | | |
|
||||
| arg | | |
|
||||
| opts | | See child_process.exec node docs |
|
||||
| opts.stdout | <code>stream.Writable</code> | If defined, child process stdout will be piped to it. |
|
||||
| opts.stderr | <code>stream.Writable</code> | If defined, child process stderr will be piped to it. |
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
interface ExecOutput {
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
}
|
||||
/**
|
||||
* Promisified child_process.exec
|
||||
*
|
||||
* @param cmd
|
||||
* @param arg
|
||||
* @param opts See child_process.exec node docs
|
||||
* @param {stream.Writable} opts.stdout If defined, child process stdout will be piped to it.
|
||||
* @param {stream.Writable} opts.stderr If defined, child process stderr will be piped to it.
|
||||
*
|
||||
* @returns {Promise<{ stdout: string, stderr: stderr }>}
|
||||
*/
|
||||
export declare function exec(...args: string[]): Promise<ExecOutput>;
|
||||
export type { ExecOutput };
|
|
@ -0,0 +1,47 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.exec = void 0;
|
||||
const child_process_1 = require("child_process");
|
||||
/**
|
||||
* Promisified child_process.exec
|
||||
*
|
||||
* @param cmd
|
||||
* @param arg
|
||||
* @param opts See child_process.exec node docs
|
||||
* @param {stream.Writable} opts.stdout If defined, child process stdout will be piped to it.
|
||||
* @param {stream.Writable} opts.stderr If defined, child process stderr will be piped to it.
|
||||
*
|
||||
* @returns {Promise<{ stdout: string, stderr: stderr }>}
|
||||
*/
|
||||
async function exec(...args) {
|
||||
let cmd = args[0];
|
||||
let argz = null;
|
||||
let opts = null;
|
||||
if (typeof args[1] === 'object' && Array.isArray(args[1])) {
|
||||
argz = args[1];
|
||||
}
|
||||
if (argz === null && typeof args[1] === 'object') {
|
||||
opts = args[1];
|
||||
}
|
||||
else if (typeof args[2] === 'object') {
|
||||
opts = args[2];
|
||||
}
|
||||
if (opts === null) {
|
||||
opts = { maxBuffer: 1024 * 1024 };
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = (0, child_process_1.exec)(cmd, opts, (err, stdout, stderr) => err ? reject(err) : resolve({
|
||||
stdout,
|
||||
stderr
|
||||
}));
|
||||
if (opts.stdout) {
|
||||
child.stdout.pipe(opts.stdout);
|
||||
}
|
||||
if (opts.stderr) {
|
||||
child.stderr.pipe(opts.stderr);
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.exec = exec;
|
||||
module.exports = { exec };
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exec/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;;;AAEZ,iDAA+C;AAO/C;;;;;;;;;;GAUG;AACI,KAAK,UAAU,IAAI,CAAC,GAAG,IAAe;IAC5C,IAAI,GAAG,GAAY,IAAI,CAAC,CAAC,CAAC,CAAA;IAC1B,IAAI,IAAI,GAAY,IAAI,CAAA;IACxB,IAAI,IAAI,GAAS,IAAI,CAAA;IAErB,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAC1D,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;KACd;IACD,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE;QACjD,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;KACd;SAAM,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE;QACvC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;KACd;IACD,IAAI,IAAI,KAAK,IAAI,EAAE;QAClB,IAAI,GAAG,EAAE,SAAS,EAAG,IAAI,GAAG,IAAI,EAAE,CAAA;KAClC;IACE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAkB,EAAE,MAAiB,EAAE,EAAE;QAC5D,MAAM,KAAK,GAAG,IAAA,oBAAO,EAAC,GAAG,EAAE,IAAI,EACjC,CAAC,GAAW,EAAE,MAAe,EAAE,MAAc,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC7E,MAAM;YACN,MAAM;SACN,CAAC,CAAC,CAAC;QACC,IAAI,IAAI,CAAC,MAAM,EAAE;YACb,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SAClC;QACD,IAAI,IAAI,CAAC,MAAM,EAAE;YACb,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SAClC;IACL,CAAC,CAAC,CAAC;AACP,CAAC;AA7BD,oBA6BC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,CAAA"}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "exec",
|
||||
"version": "1.0.0",
|
||||
"description": "<a name=\"exec\"></a>",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<a name="exit"></a>
|
||||
|
||||
## exit(msg, code)
|
||||
Exit process with either a 0 code or other
|
||||
specified failure code. Print message to console first.
|
||||
|
||||
**Kind**: global function
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| msg | <code>string</code> | | Reason for exit |
|
||||
| code | <code>integer</code> | <code>0</code> | process exit code, default 0 |
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* Exit process with either a 0 code or other
|
||||
* specified failure code. Print message to console first.
|
||||
*
|
||||
* @param {string} msg Reason for exit
|
||||
* @param {integer} code process exit code, default 0
|
||||
**/
|
||||
declare function exit(msg: string, code?: number): void;
|
|
@ -0,0 +1,20 @@
|
|||
'use strict';
|
||||
/**
|
||||
* Exit process with either a 0 code or other
|
||||
* specified failure code. Print message to console first.
|
||||
*
|
||||
* @param {string} msg Reason for exit
|
||||
* @param {integer} code process exit code, default 0
|
||||
**/
|
||||
function exit(msg, code = 0) {
|
||||
if (code === 0) {
|
||||
console.log(msg);
|
||||
process.exit();
|
||||
}
|
||||
else {
|
||||
console.error(msg);
|
||||
process.exit(code);
|
||||
}
|
||||
}
|
||||
module.exports = { exit };
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exit/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb;;;;;;IAMI;AAEJ,SAAS,IAAI,CAAE,GAAY,EAAE,OAAgB,CAAC;IAC7C,IAAI,IAAI,KAAK,CAAC,EAAE;QACf,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjB,OAAO,CAAC,IAAI,EAAE,CAAC;KACf;SAAM;QACN,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;KACnB;AACF,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,CAAC"}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "exit",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
## Modules
|
||||
|
||||
<dl>
|
||||
<dt><a href="#module_ffmpeg">ffmpeg</a></dt>
|
||||
<dd></dd>
|
||||
<dt><a href="#module_lib/ffmpeg">lib/ffmpeg</a></dt>
|
||||
<dd></dd>
|
||||
</dl>
|
||||
|
||||
<a name="module_ffmpeg"></a>
|
||||
|
||||
## ffmpeg
|
||||
<a name="module_lib/ffmpeg"></a>
|
||||
|
||||
## lib/ffmpeg
|
||||
|
||||
* [lib/ffmpeg](#module_lib/ffmpeg)
|
||||
* [~Creates an ffmpeg class](#module_lib/ffmpeg..Creates an ffmpeg class)
|
||||
* [new Creates an ffmpeg class(sys)](#new_module_lib/ffmpeg..Creates an ffmpeg class_new)
|
||||
* [~FFMPEG](#module_lib/ffmpeg..FFMPEG)
|
||||
* [.init()](#module_lib/ffmpeg..FFMPEG+init)
|
||||
* [.padded_frame(i)](#module_lib/ffmpeg..FFMPEG+padded_frame) ⇒ <code>string</code>
|
||||
* [.parseStderr(line)](#module_lib/ffmpeg..FFMPEG+parseStderr)
|
||||
* [.frame(state, light)](#module_lib/ffmpeg..FFMPEG+frame) ⇒ <code>string</code>
|
||||
* [.frames(video, obj)](#module_lib/ffmpeg..FFMPEG+frames) ⇒ <code>?</code>
|
||||
* [.clear(frame)](#module_lib/ffmpeg..FFMPEG+clear) ⇒ <code>boolean</code>
|
||||
* [.clearAll()](#module_lib/ffmpeg..FFMPEG+clearAll)
|
||||
* [.checkDir()](#module_lib/ffmpeg..FFMPEG+checkDir)
|
||||
|
||||
<a name="module_lib/ffmpeg..Creates an ffmpeg class"></a>
|
||||
|
||||
### lib/ffmpeg~Creates an ffmpeg class
|
||||
**Kind**: inner class of [<code>lib/ffmpeg</code>](#module_lib/ffmpeg)
|
||||
<a name="new_module_lib/ffmpeg..Creates an ffmpeg class_new"></a>
|
||||
|
||||
#### new Creates an ffmpeg class(sys)
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| sys | <code>object</code> | System object to be used to get temp directory |
|
||||
|
||||
<a name="module_lib/ffmpeg..FFMPEG"></a>
|
||||
|
||||
### lib/ffmpeg~FFMPEG
|
||||
Class representing all ffmpeg features.
|
||||
|
||||
**Kind**: inner class of [<code>lib/ffmpeg</code>](#module_lib/ffmpeg)
|
||||
|
||||
* [~FFMPEG](#module_lib/ffmpeg..FFMPEG)
|
||||
* [.init()](#module_lib/ffmpeg..FFMPEG+init)
|
||||
* [.padded_frame(i)](#module_lib/ffmpeg..FFMPEG+padded_frame) ⇒ <code>string</code>
|
||||
* [.parseStderr(line)](#module_lib/ffmpeg..FFMPEG+parseStderr)
|
||||
* [.frame(state, light)](#module_lib/ffmpeg..FFMPEG+frame) ⇒ <code>string</code>
|
||||
* [.frames(video, obj)](#module_lib/ffmpeg..FFMPEG+frames) ⇒ <code>?</code>
|
||||
* [.clear(frame)](#module_lib/ffmpeg..FFMPEG+clear) ⇒ <code>boolean</code>
|
||||
* [.clearAll()](#module_lib/ffmpeg..FFMPEG+clearAll)
|
||||
* [.checkDir()](#module_lib/ffmpeg..FFMPEG+checkDir)
|
||||
|
||||
<a name="module_lib/ffmpeg..FFMPEG+init"></a>
|
||||
|
||||
#### ffmpeG.init()
|
||||
Async method to call async functions from constructor
|
||||
|
||||
**Kind**: instance method of [<code>FFMPEG</code>](#module_lib/ffmpeg..FFMPEG)
|
||||
<a name="module_lib/ffmpeg..FFMPEG+padded_frame"></a>
|
||||
|
||||
#### ffmpeG.padded\_frame(i) ⇒ <code>string</code>
|
||||
Add padding to a number to 5 places. Return a string.
|
||||
|
||||
**Kind**: instance method of [<code>FFMPEG</code>](#module_lib/ffmpeg..FFMPEG)
|
||||
**Returns**: <code>string</code> - Padded string
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| i | <code>integer</code> | Integer to pad |
|
||||
|
||||
<a name="module_lib/ffmpeg..FFMPEG+parseStderr"></a>
|
||||
|
||||
#### ffmpeG.parseStderr(line)
|
||||
Parse the stderr output of ffmpeg
|
||||
|
||||
**Kind**: instance method of [<code>FFMPEG</code>](#module_lib/ffmpeg..FFMPEG)
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| line | <code>string</code> | Stderr line |
|
||||
|
||||
<a name="module_lib/ffmpeg..FFMPEG+frame"></a>
|
||||
|
||||
#### ffmpeG.frame(state, light) ⇒ <code>string</code>
|
||||
Render a single frame from a video or image to a png.
|
||||
|
||||
**Kind**: instance method of [<code>FFMPEG</code>](#module_lib/ffmpeg..FFMPEG)
|
||||
**Returns**: <code>string</code> - Path of frame
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| state | <code>object</code> | State object containing file data |
|
||||
| light | <code>object</code> | Object containing color information for frame |
|
||||
|
||||
<a name="module_lib/ffmpeg..FFMPEG+frames"></a>
|
||||
|
||||
#### ffmpeG.frames(video, obj) ⇒ <code>?</code>
|
||||
Render all frames in a video to the temp directory.
|
||||
Not in use.
|
||||
|
||||
**Kind**: instance method of [<code>FFMPEG</code>](#module_lib/ffmpeg..FFMPEG)
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| video | <code>string</code> | Path to video |
|
||||
| obj | <code>object</code> | Not sure |
|
||||
|
||||
<a name="module_lib/ffmpeg..FFMPEG+clear"></a>
|
||||
|
||||
#### ffmpeG.clear(frame) ⇒ <code>boolean</code>
|
||||
Clears a specific frame from the tmp directory
|
||||
|
||||
**Kind**: instance method of [<code>FFMPEG</code>](#module_lib/ffmpeg..FFMPEG)
|
||||
**Returns**: <code>boolean</code> - True if successful, false if not
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| frame | <code>integer</code> | Integer of frame to clear |
|
||||
|
||||
<a name="module_lib/ffmpeg..FFMPEG+clearAll"></a>
|
||||
|
||||
#### ffmpeG.clearAll()
|
||||
Deletes all frames in temp directory.
|
||||
|
||||
**Kind**: instance method of [<code>FFMPEG</code>](#module_lib/ffmpeg..FFMPEG)
|
||||
<a name="module_lib/ffmpeg..FFMPEG+checkDir"></a>
|
||||
|
||||
#### ffmpeG.checkDir()
|
||||
Checks if mcopy temp directory exists. If it doesn't,
|
||||
creates it.
|
||||
|
||||
**Kind**: instance method of [<code>FFMPEG</code>](#module_lib/ffmpeg..FFMPEG)
|
|
@ -0,0 +1,89 @@
|
|||
import type { FilmOutState } from 'filmout';
|
||||
import type { System } from 'system';
|
||||
import type { LightState } from 'light';
|
||||
interface StdErr {
|
||||
frame: number;
|
||||
fps: number;
|
||||
time: string;
|
||||
speed: number;
|
||||
size: string;
|
||||
remaining?: number;
|
||||
progress?: number;
|
||||
estimated?: number;
|
||||
}
|
||||
/** @module lib/ffmpeg */
|
||||
/**
|
||||
* Class representing all ffmpeg features.
|
||||
*/
|
||||
export declare class FFMPEG {
|
||||
private bin;
|
||||
private log;
|
||||
private id;
|
||||
private TMPDIR;
|
||||
private child;
|
||||
onProgress: Function;
|
||||
/**
|
||||
* @constructor
|
||||
* Creates an ffmpeg class
|
||||
*
|
||||
* @param {object} sys System object to be used to get temp directory
|
||||
**/
|
||||
constructor(sys: System);
|
||||
/**
|
||||
* Async method to call async functions from constructor
|
||||
**/
|
||||
init(): Promise<void>;
|
||||
/**
|
||||
* Add padding to a number to 5 places. Return a string.
|
||||
*
|
||||
* @param {integer} i Integer to pad
|
||||
*
|
||||
* @returns {string} Padded string
|
||||
**/
|
||||
private padded_frame;
|
||||
/**
|
||||
* Parse the stderr output of ffmpeg
|
||||
*
|
||||
* @param {string} line Stderr line
|
||||
**/
|
||||
private parseStderr;
|
||||
/**
|
||||
* Render a single frame from a video or image to a png.
|
||||
*
|
||||
* @param {object} state State object containing file data
|
||||
* @param {object} light Object containing color information for frame
|
||||
*
|
||||
* @returns {string} Path of frame
|
||||
**/
|
||||
frame(state: FilmOutState, light: LightState): Promise<string>;
|
||||
/**
|
||||
* Render all frames in a video to the temp directory.
|
||||
* Not in use.
|
||||
*
|
||||
* @param {string} video Path to video
|
||||
* @param {object} obj Not sure
|
||||
*
|
||||
* @returns {?}
|
||||
**/
|
||||
frames(state: FilmOutState): Promise<unknown>;
|
||||
cancel(): void;
|
||||
/**
|
||||
* Clears a specific frame from the tmp directory
|
||||
*
|
||||
* @param {integer} frame Integer of frame to clear
|
||||
*
|
||||
* @returns {boolean} True if successful, false if not
|
||||
**/
|
||||
clear(state: any): Promise<boolean>;
|
||||
/**
|
||||
* Deletes all frames in temp directory.
|
||||
*
|
||||
**/
|
||||
clearAll(): Promise<void>;
|
||||
/**
|
||||
* Checks if mcopy temp directory exists. If it doesn't,
|
||||
* creates it.
|
||||
**/
|
||||
private checkDir;
|
||||
}
|
||||
export type { StdErr };
|
|
@ -0,0 +1,346 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.FFMPEG = void 0;
|
||||
/** @module ffmpeg **/
|
||||
const path_1 = require("path");
|
||||
const fs_extra_1 = require("fs-extra");
|
||||
const exec_1 = require("exec");
|
||||
const child_process_1 = require("child_process");
|
||||
const log_1 = require("log");
|
||||
/** @module lib/ffmpeg */
|
||||
/**
|
||||
* Class representing all ffmpeg features.
|
||||
*/
|
||||
class FFMPEG {
|
||||
/**
|
||||
* @constructor
|
||||
* Creates an ffmpeg class
|
||||
*
|
||||
* @param {object} sys System object to be used to get temp directory
|
||||
**/
|
||||
constructor(sys) {
|
||||
this.id = 'ffmpeg';
|
||||
this.onProgress = () => { };
|
||||
this.bin = sys.deps.ffmpeg;
|
||||
this.TMPDIR = (0, path_1.join)(sys.tmp, 'mcopy_digital');
|
||||
this.init();
|
||||
}
|
||||
/**
|
||||
* Async method to call async functions from constructor
|
||||
**/
|
||||
async init() {
|
||||
this.log = await (0, log_1.Log)({ label: this.id });
|
||||
await this.checkDir();
|
||||
}
|
||||
/**
|
||||
* Add padding to a number to 5 places. Return a string.
|
||||
*
|
||||
* @param {integer} i Integer to pad
|
||||
*
|
||||
* @returns {string} Padded string
|
||||
**/
|
||||
padded_frame(i) {
|
||||
let len = (i + '').length;
|
||||
let str = i + '';
|
||||
for (let x = 0; x < 8 - len; x++) {
|
||||
str = '0' + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
/**
|
||||
* Parse the stderr output of ffmpeg
|
||||
*
|
||||
* @param {string} line Stderr line
|
||||
**/
|
||||
parseStderr(line) {
|
||||
//frame= 6416 fps= 30 q=31.0 size= 10251kB time=00:03:34.32 bitrate= 391.8kbits/s speed= 1x
|
||||
const obj = {
|
||||
frame: 0,
|
||||
fps: 0,
|
||||
time: '',
|
||||
speed: 0,
|
||||
size: ''
|
||||
};
|
||||
let frameStr;
|
||||
let fpsStr;
|
||||
let speedStr;
|
||||
if (line.substring(0, 'frame='.length) === 'frame=') {
|
||||
try {
|
||||
frameStr = line.split('frame=')[1].split('fps=')[0];
|
||||
obj.frame = parseInt(frameStr);
|
||||
fpsStr = line.split('fps=')[1].split('q=')[0];
|
||||
obj.fps = parseFloat(fpsStr);
|
||||
obj.time = line.split('time=')[1].split('bitrate=')[0];
|
||||
speedStr = line.split('speed=')[1].trim().replace('x', '');
|
||||
obj.speed = parseFloat(speedStr);
|
||||
obj.size = line.split('size=')[1].split('time=')[0].trim();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error parsing stderr line', err);
|
||||
this.log.info(line);
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
else {
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
/**
|
||||
* Render a single frame from a video or image to a png.
|
||||
*
|
||||
* @param {object} state State object containing file data
|
||||
* @param {object} light Object containing color information for frame
|
||||
*
|
||||
* @returns {string} Path of frame
|
||||
**/
|
||||
async frame(state, light) {
|
||||
const frameNum = state.frame;
|
||||
const video = state.directory ? state.files[frameNum] : state.path;
|
||||
const w = state.info.width;
|
||||
const h = state.info.height;
|
||||
const padded = this.padded_frame(frameNum);
|
||||
let ext = 'png';
|
||||
let rgb = light.color;
|
||||
let rgba;
|
||||
let tmpoutput;
|
||||
let cmd;
|
||||
let output;
|
||||
let fileExists = false;
|
||||
let scale = '';
|
||||
if (state.directory) {
|
||||
return video;
|
||||
}
|
||||
if (w && h) {
|
||||
scale = `,scale=trunc(ih*dar):${h}`; //:force_original_aspect_ratio=decrease,pad=${w}:${h}:(ow-iw)/2:(oh-ih)/2
|
||||
}
|
||||
tmpoutput = (0, path_1.join)(this.TMPDIR, `${state.hash}-export-${padded}.${ext}`);
|
||||
try {
|
||||
fileExists = await (0, fs_extra_1.exists)(tmpoutput);
|
||||
}
|
||||
catch (err) {
|
||||
//
|
||||
}
|
||||
if (fileExists) {
|
||||
this.log.info(`File ${tmpoutput} exists`);
|
||||
return tmpoutput;
|
||||
}
|
||||
//
|
||||
cmd = `${this.bin} -hwaccel auto -y -i "${video}" -vf "select='gte(n\\,${frameNum})'${scale}" -vframes 1 -compression_algo raw -pix_fmt rgb24 -crf 0 "${tmpoutput}"`;
|
||||
//cmd2 = `${this.convert} "${tmpoutput}" -resize ${w}x${h} -size ${w}x${h} xc:"rgb(${rgb[0]},${rgb[1]},${rgb[2]})" +swap -compose Darken -composite "${tmpoutput}"`;
|
||||
//ffmpeg -i "${video}" -ss 00:00:07.000 -vframes 1 "export-${time}.jpg"
|
||||
//ffmpeg -i "${video}" -compression_algo raw -pix_fmt rgb24 "export-%05d.tiff"
|
||||
//-vf "select=gte(n\,${frame})" -compression_algo raw -pix_fmt rgb24 "export-${padded}.png"
|
||||
try {
|
||||
this.log.info(cmd);
|
||||
output = await (0, exec_1.exec)(cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
if (output && output.stdout)
|
||||
this.log.info(`"${output.stdout.trim()}"`);
|
||||
if (rgb[0] !== 255 || rgb[1] !== 255 || rgb[2] !== 255) {
|
||||
rgb = rgb.map((e) => {
|
||||
return typeof e === 'string' ? parseInt(e) : e;
|
||||
});
|
||||
rgba = { r: rgb[0], g: rgb[1], b: rgb[2], a: 255 };
|
||||
try {
|
||||
//await Frame.blend(tmpoutput, rgba, tmpoutput);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
return tmpoutput;
|
||||
}
|
||||
/**
|
||||
* Render all frames in a video to the temp directory.
|
||||
* Not in use.
|
||||
*
|
||||
* @param {string} video Path to video
|
||||
* @param {object} obj Not sure
|
||||
*
|
||||
* @returns {?}
|
||||
**/
|
||||
async frames(state) {
|
||||
const video = state.path;
|
||||
const w = state.info.width;
|
||||
const h = state.info.height;
|
||||
const tmppath = this.TMPDIR;
|
||||
let ext = 'png';
|
||||
let tmpoutput = (0, path_1.join)(tmppath, `${state.hash}-export-%08d.${ext}`);
|
||||
let args;
|
||||
let output;
|
||||
let estimated = -1;
|
||||
//cmd = `${this.bin} -y -i "${video}" -vf "${scale}" -compression_algo raw -pix_fmt rgb24 -crf 0 "${tmpoutput}"`;
|
||||
args = [
|
||||
'-hwaccel',
|
||||
'auto',
|
||||
'-y',
|
||||
'-i', video
|
||||
];
|
||||
if (w && h) {
|
||||
args.push('-vf');
|
||||
args.push(`scale=${w}:${h}`);
|
||||
}
|
||||
args = args.concat([
|
||||
'-compression_algo', 'raw',
|
||||
'-pix_fmt', 'rgb24',
|
||||
'-crf', '0',
|
||||
tmpoutput
|
||||
]);
|
||||
//console.dir(args)
|
||||
//console.dir(state)
|
||||
try {
|
||||
await (0, fs_extra_1.mkdir)(tmppath);
|
||||
}
|
||||
catch (err) {
|
||||
if (err.code && err.code === 'EEXIST') {
|
||||
//directory exists
|
||||
}
|
||||
else {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
//ffmpeg -i "${video}" -compression_algo raw -pix_fmt rgb24 "${tmpoutput}"
|
||||
return new Promise((resolve, reject) => {
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
this.log.info(`${this.bin} ${args.join(' ')}`);
|
||||
this.child = (0, child_process_1.spawn)(this.bin, args);
|
||||
this.child.on('exit', function (code) {
|
||||
//console.log('GOT TO EXIT');
|
||||
if (code === 0) {
|
||||
this.log.info(stderr);
|
||||
this.log.info(stdout);
|
||||
return resolve(true);
|
||||
}
|
||||
else {
|
||||
this.log.error(`Process exited with code: ${code}`);
|
||||
this.log.error(stderr);
|
||||
return reject(stderr + stdout);
|
||||
}
|
||||
}.bind(this));
|
||||
this.child.stdout.on('data', (data) => {
|
||||
const line = data.toString();
|
||||
stdout += line;
|
||||
});
|
||||
this.child.stderr.on('data', (data) => {
|
||||
const line = data.toString();
|
||||
const obj = this.parseStderr(line);
|
||||
if (obj.frame && state.frames) {
|
||||
obj.progress = obj.frame / state.frames;
|
||||
}
|
||||
if (obj.frame && obj.speed && state.frames && state.info.fps) {
|
||||
//scale by speed
|
||||
obj.remaining = ((state.frames - obj.frame) / state.info.fps) / obj.speed;
|
||||
obj.estimated = state.info.seconds / obj.speed;
|
||||
if (obj.estimated > estimated) {
|
||||
estimated = obj.estimated;
|
||||
}
|
||||
}
|
||||
if (obj.frame) {
|
||||
//log.info(`${input.name} ${obj.frame}/${input.frames} ${Math.round(obj.progress * 1000) / 10}% ${Math.round(obj.remaining)} seconds remaining of ${Math.round(obj.estimated)}`);
|
||||
this.onProgress(obj);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
cancel() {
|
||||
if (this.child) {
|
||||
this.child.kill();
|
||||
this.log.info(`Stopped exporting sequence with ffmpeg`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Clears a specific frame from the tmp directory
|
||||
*
|
||||
* @param {integer} frame Integer of frame to clear
|
||||
*
|
||||
* @returns {boolean} True if successful, false if not
|
||||
**/
|
||||
async clear(state) {
|
||||
const padded = this.padded_frame(state.frame);
|
||||
let ext = 'png';
|
||||
let tmppath;
|
||||
let fileExists;
|
||||
tmppath = (0, path_1.join)(this.TMPDIR, `${state.hash}-export-${padded}.${ext}`);
|
||||
try {
|
||||
fileExists = await (0, fs_extra_1.exists)(tmppath);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
if (!fileExists)
|
||||
return false;
|
||||
try {
|
||||
await (0, fs_extra_1.unlink)(tmppath);
|
||||
this.log.info(`Cleared frame ${tmppath}`);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Deletes all frames in temp directory.
|
||||
*
|
||||
**/
|
||||
async clearAll() {
|
||||
const tmppath = this.TMPDIR;
|
||||
let files;
|
||||
try {
|
||||
files = await (0, fs_extra_1.readdir)(tmppath);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
files = files.filter((file) => {
|
||||
if (file.indexOf('-export-') !== -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (files) {
|
||||
files.forEach(async (file, index) => {
|
||||
try {
|
||||
await (0, fs_extra_1.unlink)((0, path_1.join)(tmppath, file));
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Checks if mcopy temp directory exists. If it doesn't,
|
||||
* creates it.
|
||||
**/
|
||||
async checkDir() {
|
||||
let fileExists;
|
||||
try {
|
||||
fileExists = await (0, fs_extra_1.exists)(this.TMPDIR);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error checking for tmp dir', err);
|
||||
}
|
||||
if (!fileExists) {
|
||||
try {
|
||||
await (0, fs_extra_1.mkdir)(this.TMPDIR);
|
||||
this.log.info(`Created tmpdir ${this.TMPDIR}`);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error creating tmp dir', err);
|
||||
}
|
||||
}
|
||||
try {
|
||||
await this.clearAll();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.FFMPEG = FFMPEG;
|
||||
module.exports = { FFMPEG };
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "ffmpeg",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<a name="module_lib/ffprobe"></a>
|
||||
|
||||
## lib/ffprobe
|
||||
|
||||
* [lib/ffprobe](#module_lib/ffprobe)
|
||||
* [~FFPROBE](#module_lib/ffprobe..FFPROBE)
|
||||
* [.parseFps()](#module_lib/ffprobe..FFPROBE+parseFps)
|
||||
* [.info(video)](#module_lib/ffprobe..FFPROBE+info) ⇒ <code>object</code>
|
||||
* [.frames(video)](#module_lib/ffprobe..FFPROBE+frames) ⇒ <code>integer</code>
|
||||
|
||||
<a name="module_lib/ffprobe..FFPROBE"></a>
|
||||
|
||||
### lib/ffprobe~FFPROBE
|
||||
Class representing all ffprobe features.
|
||||
|
||||
**Kind**: inner class of [<code>lib/ffprobe</code>](#module_lib/ffprobe)
|
||||
|
||||
* [~FFPROBE](#module_lib/ffprobe..FFPROBE)
|
||||
* [.parseFps()](#module_lib/ffprobe..FFPROBE+parseFps)
|
||||
* [.info(video)](#module_lib/ffprobe..FFPROBE+info) ⇒ <code>object</code>
|
||||
* [.frames(video)](#module_lib/ffprobe..FFPROBE+frames) ⇒ <code>integer</code>
|
||||
|
||||
<a name="module_lib/ffprobe..FFPROBE+parseFps"></a>
|
||||
|
||||
#### ffprobE.parseFps()
|
||||
Parse the fps entry into a float representing the fps of a video
|
||||
|
||||
**Kind**: instance method of [<code>FFPROBE</code>](#module_lib/ffprobe..FFPROBE)
|
||||
<a name="module_lib/ffprobe..FFPROBE+info"></a>
|
||||
|
||||
#### ffprobE.info(video) ⇒ <code>object</code>
|
||||
Get info on a video in json format. Use for filmout.
|
||||
|
||||
**Kind**: instance method of [<code>FFPROBE</code>](#module_lib/ffprobe..FFPROBE)
|
||||
**Returns**: <code>object</code> - Video info in an object
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| video | <code>string</code> | Path to video |
|
||||
|
||||
<a name="module_lib/ffprobe..FFPROBE+frames"></a>
|
||||
|
||||
#### ffprobE.frames(video) ⇒ <code>integer</code>
|
||||
Count the number of frames in the video using one of two methods.
|
||||
The first uses -select_streams and is very fast. The second uses
|
||||
-count_frames and is VERY slow.
|
||||
|
||||
**Kind**: instance method of [<code>FFPROBE</code>](#module_lib/ffprobe..FFPROBE)
|
||||
**Returns**: <code>integer</code> - Number of frames in video
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| video | <code>string</code> | Path to video |
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import type { System } from 'system';
|
||||
/** @module lib/ffprobe */
|
||||
/**
|
||||
* Class representing all ffprobe features.
|
||||
*/
|
||||
export declare class FFPROBE {
|
||||
private bin;
|
||||
private log;
|
||||
constructor(sys: System);
|
||||
private init;
|
||||
/**
|
||||
* Parse the fps entry into a float representing the fps of a video
|
||||
**/
|
||||
private parseFps;
|
||||
/**
|
||||
* Get info on a video in json format. Use for filmout.
|
||||
*
|
||||
* @param {string} video Path to video
|
||||
*
|
||||
* @returns {object} Video info in an object
|
||||
**/
|
||||
info(video: string): Promise<any>;
|
||||
/**
|
||||
* Count the number of frames in the video using one of two methods.
|
||||
* The first uses -select_streams and is very fast. The second uses
|
||||
* -count_frames and is VERY slow.
|
||||
*
|
||||
* @param {string} video Path to video
|
||||
*
|
||||
* @returns {integer} Number of frames in video
|
||||
**/
|
||||
frames(video: string): Promise<any>;
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.FFPROBE = void 0;
|
||||
const fs_extra_1 = require("fs-extra");
|
||||
const path_1 = require("path");
|
||||
const exec_1 = require("exec");
|
||||
const log_1 = require("log");
|
||||
/** @module lib/ffprobe */
|
||||
/**
|
||||
* Class representing all ffprobe features.
|
||||
*/
|
||||
class FFPROBE {
|
||||
constructor(sys) {
|
||||
this.bin = sys.deps.ffprobe;
|
||||
this.init();
|
||||
}
|
||||
async init() {
|
||||
this.log = await (0, log_1.Log)({ label: 'ffprobe' });
|
||||
}
|
||||
/**
|
||||
* Parse the fps entry into a float representing the fps of a video
|
||||
**/
|
||||
parseFps(fpsStr) {
|
||||
let fps = 30.0;
|
||||
let parts;
|
||||
if (fpsStr.indexOf('/') !== -1) {
|
||||
parts = fpsStr.split('/');
|
||||
fps = parseFloat(parts[0]) / parseFloat(parts[1]);
|
||||
}
|
||||
else {
|
||||
fps = parseFloat(fpsStr);
|
||||
}
|
||||
return fps;
|
||||
}
|
||||
/**
|
||||
* Get info on a video in json format. Use for filmout.
|
||||
*
|
||||
* @param {string} video Path to video
|
||||
*
|
||||
* @returns {object} Video info in an object
|
||||
**/
|
||||
async info(video) {
|
||||
const cmd = `${this.bin} -v quiet -print_format json -show_format -show_streams "${video}"`;
|
||||
let fileExists;
|
||||
let raw;
|
||||
let json;
|
||||
let vid; //whether video has stream with video data
|
||||
try {
|
||||
fileExists = await (0, fs_extra_1.exists)(video);
|
||||
}
|
||||
catch (err) {
|
||||
return exit(err, 5);
|
||||
}
|
||||
if (!fileExists) {
|
||||
//return exit(`File ${video} does not exist`, 6);
|
||||
this.log.error(new Error(`File ${video} does not exist`));
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
this.log.info(cmd);
|
||||
raw = await (0, exec_1.exec)(cmd);
|
||||
}
|
||||
catch (err) {
|
||||
//return exit(err, 7);
|
||||
this.log.error(err);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
json = JSON.parse(raw.stdout);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error('Error parsing stdout', err);
|
||||
this.log.error(raw.stdout);
|
||||
return raw.stdout;
|
||||
}
|
||||
if (json.format && json.format.duration) {
|
||||
json.seconds = parseFloat(json.format.duration);
|
||||
}
|
||||
if (json && json.streams) {
|
||||
vid = json.streams.find((stream) => {
|
||||
if (stream.width && stream.height)
|
||||
return stream;
|
||||
});
|
||||
}
|
||||
if (vid) {
|
||||
json.width = vid.width;
|
||||
json.height = vid.height;
|
||||
json.fps = this.parseFps(vid.r_frame_rate);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
/**
|
||||
* Count the number of frames in the video using one of two methods.
|
||||
* The first uses -select_streams and is very fast. The second uses
|
||||
* -count_frames and is VERY slow.
|
||||
*
|
||||
* @param {string} video Path to video
|
||||
*
|
||||
* @returns {integer} Number of frames in video
|
||||
**/
|
||||
async frames(video) {
|
||||
const ext = (0, path_1.extname)(video.toLowerCase());
|
||||
let cmd = `${this.bin} -v error -select_streams v:0 -show_entries stream=nb_frames -of default=nokey=1:noprint_wrappers=1 "${video}"`;
|
||||
let backup_cmd = `${this.bin} -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 "${video}"`;
|
||||
let gif_cmd = `identify -format "%n\n" "${video}" | head -1`;
|
||||
let fileExists;
|
||||
let raw;
|
||||
let frames;
|
||||
try {
|
||||
fileExists = await (0, fs_extra_1.exists)(video);
|
||||
}
|
||||
catch (err) {
|
||||
//return exit(err, 5);
|
||||
this.log.error(err);
|
||||
return false;
|
||||
}
|
||||
if (!fileExists) {
|
||||
//return exit(`File ${video} does not exist`, 6);
|
||||
console.error(new Error(`File ${video} does not exist`));
|
||||
return false;
|
||||
}
|
||||
if (ext === '.mkv') {
|
||||
cmd = backup_cmd;
|
||||
}
|
||||
else if (ext === '.gif') {
|
||||
cmd = gif_cmd;
|
||||
}
|
||||
try {
|
||||
this.log.info(cmd);
|
||||
raw = await (0, exec_1.exec)(cmd);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
frames = parseInt(raw.stdout);
|
||||
}
|
||||
catch (err) {
|
||||
return raw.stdout;
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
}
|
||||
exports.FFPROBE = FFPROBE;
|
||||
/*
|
||||
function map (obj : any) {
|
||||
console.dir(obj);
|
||||
}
|
||||
*/
|
||||
module.exports = { FFPROBE };
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ffprobe/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEb,uCAAkC;AAClC,+BAA+B;AAC/B,+BAA4B;AAC5B,6BAA0B;AAI1B,0BAA0B;AAE1B;;GAEG;AAEH,MAAa,OAAO;IAInB,YAAa,GAAY;QACxB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;IAEO,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,GAAG,GAAG,MAAM,IAAA,SAAG,EAAC,EAAE,KAAK,EAAG,SAAS,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED;;QAEI;IACI,QAAQ,CAAE,MAAe;QAChC,IAAI,GAAG,GAAY,IAAI,CAAC;QACxB,IAAI,KAAgB,CAAC;QACrB,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE;YAC/B,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC1B,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;SAClD;aAAM;YACN,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;SACzB;QACD,OAAO,GAAG,CAAA;IACX,CAAC;IACD;;;;;;QAMI;IACG,KAAK,CAAC,IAAI,CAAE,KAAc;QAChC,MAAM,GAAG,GAAY,GAAG,IAAI,CAAC,GAAG,4DAA4D,KAAK,GAAG,CAAA;QACpG,IAAI,UAAoB,CAAC;QACzB,IAAI,GAAS,CAAC;QACd,IAAI,IAAU,CAAC;QACf,IAAI,GAAS,CAAC,CAAC,0CAA0C;QAEzD,IAAI;YACH,UAAU,GAAG,MAAM,IAAA,iBAAM,EAAC,KAAK,CAAC,CAAC;SACjC;QAAC,OAAO,GAAG,EAAE;YACb,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;SACpB;QACD,IAAI,CAAC,UAAU,EAAE;YAChB,iDAAiD;YACjD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,KAAK,iBAAiB,CAAC,CAAC,CAAC;YAC1D,OAAO,KAAK,CAAA;SACZ;QAED,IAAI;YACH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,GAAG,MAAM,IAAA,WAAI,EAAC,GAAG,CAAC,CAAC;SACtB;QAAC,OAAO,GAAG,EAAE;YACb,sBAAsB;YACtB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO,KAAK,CAAA;SACZ;QAED,IAAI;YACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;SAC9B;QAAC,OAAO,GAAG,EAAE;YACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC;YAC5C,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC3B,OAAO,GAAG,CAAC,MAAM,CAAC;SAClB;QAED,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;YACxC,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;SAChD;QAED,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE;YACzB,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAY,EAAE,EAAE;gBACxC,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM;oBAAE,OAAO,MAAM,CAAC;YAClD,CAAC,CAAC,CAAC;SACH;QAED,IAAI,GAAG,EAAE;YACR,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;YACvB,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;YACzB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;SAC1C;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IACD;;;;;;;;QAQI;IACG,KAAK,CAAC,MAAM,CAAE,KAAc;QAClC,MAAM,GAAG,GAAY,IAAA,cAAO,EAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QAClD,IAAI,GAAG,GAAY,GAAG,IAAI,CAAC,GAAG,wGAAwG,KAAK,GAAG,CAAC;QAC/I,IAAI,UAAU,GAAY,GAAG,IAAI,CAAC,GAAG,2HAA2H,KAAK,GAAG,CAAC;QACzK,IAAI,OAAO,GAAY,4BAA4B,KAAK,aAAa,CAAA;QACrE,IAAI,UAAoB,CAAC;QACzB,IAAI,GAAS,CAAC;QACd,IAAI,MAAe,CAAC;QAEpB,IAAI;YACH,UAAU,GAAG,MAAM,IAAA,iBAAM,EAAC,KAAK,CAAC,CAAC;SACjC;QAAC,OAAO,GAAG,EAAE;YACb,sBAAsB;YACtB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO,KAAK,CAAA;SACZ;QACD,IAAI,CAAC,UAAU,EAAE;YAChB,iDAAiD;YACjD,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,KAAK,iBAAiB,CAAC,CAAC,CAAC;YACzD,OAAO,KAAK,CAAC;SACb;QAED,IAAI,GAAG,KAAK,MAAM,EAAE;YACnB,GAAG,GAAG,UAAU,CAAC;SACjB;aAAM,IAAI,GAAG,KAAK,MAAM,EAAE;YAC1B,GAAG,GAAG,OAAO,CAAC;SACd;QACD,IAAI;YACH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,GAAG,MAAM,IAAA,WAAI,EAAC,GAAG,CAAC,CAAC;SACtB;QAAC,OAAO,GAAG,EAAE;YACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO,KAAK,CAAC;SACb;QAED,IAAI;YACH,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;SAC9B;QAAC,OAAO,GAAG,EAAE;YACb,OAAO,GAAG,CAAC,MAAM,CAAC;SAClB;QAED,OAAO,MAAM,CAAC;IACf,CAAC;CACD;AA3ID,0BA2IC;AAED;;;;EAIE;AAEF,MAAM,CAAC,OAAO,GAAG,EAAE,OAAO,EAAE,CAAC"}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "ffprobe",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
<a name="module_lib/filmout"></a>
|
||||
|
||||
## lib/filmout
|
||||
|
||||
* [lib/filmout](#module_lib/filmout)
|
||||
* [~FilmOut](#module_lib/filmout..FilmOut)
|
||||
* [.init()](#module_lib/filmout..FilmOut+init)
|
||||
* [.listen()](#module_lib/filmout..FilmOut+listen)
|
||||
* [.hash(data)](#module_lib/filmout..FilmOut+hash)
|
||||
* [.set(dir)](#module_lib/filmout..FilmOut+set)
|
||||
* [.move()](#module_lib/filmout..FilmOut+move) ⇒ <code>number</code>
|
||||
* [.start()](#module_lib/filmout..FilmOut+start)
|
||||
* [.end()](#module_lib/filmout..FilmOut+end)
|
||||
* [.onConnect(evt, arg)](#module_lib/filmout..FilmOut+onConnect) ⇒ <code>boolean</code>
|
||||
* [.onPreExport(evt, arg)](#module_lib/filmout..FilmOut+onPreExport) ⇒ <code>any</code>
|
||||
* [.isGifAnimated(pathStr)](#module_lib/filmout..FilmOut+isGifAnimated) ⇒ <code>boolean</code>
|
||||
* [.stillInfo(pathStr)](#module_lib/filmout..FilmOut+stillInfo) ⇒ <code>object</code>
|
||||
* [.dirInfo(images)](#module_lib/filmout..FilmOut+dirInfo) ⇒ <code>object</code>
|
||||
* [.dirList(pathStr)](#module_lib/filmout..FilmOut+dirList) ⇒ <code>array</code>
|
||||
* [.previewFrame(evt, arg)](#module_lib/filmout..FilmOut+previewFrame)
|
||||
* [.preview(evt, arg)](#module_lib/filmout..FilmOut+preview)
|
||||
* [.focus()](#module_lib/filmout..FilmOut+focus)
|
||||
* [.field()](#module_lib/filmout..FilmOut+field)
|
||||
* [.meter()](#module_lib/filmout..FilmOut+meter)
|
||||
* [.close()](#module_lib/filmout..FilmOut+close)
|
||||
* [.onDisplay()](#module_lib/filmout..FilmOut+onDisplay)
|
||||
|
||||
<a name="module_lib/filmout..FilmOut"></a>
|
||||
|
||||
### lib/filmout~FilmOut
|
||||
Class representing all filmout features.
|
||||
|
||||
**Kind**: inner class of [<code>lib/filmout</code>](#module_lib/filmout)
|
||||
|
||||
* [~FilmOut](#module_lib/filmout..FilmOut)
|
||||
* [.init()](#module_lib/filmout..FilmOut+init)
|
||||
* [.listen()](#module_lib/filmout..FilmOut+listen)
|
||||
* [.hash(data)](#module_lib/filmout..FilmOut+hash)
|
||||
* [.set(dir)](#module_lib/filmout..FilmOut+set)
|
||||
* [.move()](#module_lib/filmout..FilmOut+move) ⇒ <code>number</code>
|
||||
* [.start()](#module_lib/filmout..FilmOut+start)
|
||||
* [.end()](#module_lib/filmout..FilmOut+end)
|
||||
* [.onConnect(evt, arg)](#module_lib/filmout..FilmOut+onConnect) ⇒ <code>boolean</code>
|
||||
* [.onPreExport(evt, arg)](#module_lib/filmout..FilmOut+onPreExport) ⇒ <code>any</code>
|
||||
* [.isGifAnimated(pathStr)](#module_lib/filmout..FilmOut+isGifAnimated) ⇒ <code>boolean</code>
|
||||
* [.stillInfo(pathStr)](#module_lib/filmout..FilmOut+stillInfo) ⇒ <code>object</code>
|
||||
* [.dirInfo(images)](#module_lib/filmout..FilmOut+dirInfo) ⇒ <code>object</code>
|
||||
* [.dirList(pathStr)](#module_lib/filmout..FilmOut+dirList) ⇒ <code>array</code>
|
||||
* [.previewFrame(evt, arg)](#module_lib/filmout..FilmOut+previewFrame)
|
||||
* [.preview(evt, arg)](#module_lib/filmout..FilmOut+preview)
|
||||
* [.focus()](#module_lib/filmout..FilmOut+focus)
|
||||
* [.field()](#module_lib/filmout..FilmOut+field)
|
||||
* [.meter()](#module_lib/filmout..FilmOut+meter)
|
||||
* [.close()](#module_lib/filmout..FilmOut+close)
|
||||
* [.onDisplay()](#module_lib/filmout..FilmOut+onDisplay)
|
||||
|
||||
<a name="module_lib/filmout..FilmOut+init"></a>
|
||||
|
||||
#### filmOut.init()
|
||||
Async function for requiring log, ipcMain and bind events.
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
<a name="module_lib/filmout..FilmOut+listen"></a>
|
||||
|
||||
#### filmOut.listen()
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
<a name="module_lib/filmout..FilmOut+hash"></a>
|
||||
|
||||
#### filmOut.hash(data)
|
||||
Create a hash of a string.
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| data | <code>string</code> | Data to produce hash of |
|
||||
|
||||
<a name="module_lib/filmout..FilmOut+set"></a>
|
||||
|
||||
#### filmOut.set(dir)
|
||||
Sets filmout direction.
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| dir | <code>boolean</code> | Direction of filmout |
|
||||
|
||||
<a name="module_lib/filmout..FilmOut+move"></a>
|
||||
|
||||
#### filmOut.move() ⇒ <code>number</code>
|
||||
Moves filmout a frame at a time.
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
**Returns**: <code>number</code> - Time since start
|
||||
<a name="module_lib/filmout..FilmOut+start"></a>
|
||||
|
||||
#### filmOut.start()
|
||||
Begin the process of exporting single frames from the video for display.
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
<a name="module_lib/filmout..FilmOut+end"></a>
|
||||
|
||||
#### filmOut.end()
|
||||
Ends the filmout process and closes the display.
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
<a name="module_lib/filmout..FilmOut+onConnect"></a>
|
||||
|
||||
#### filmOut.onConnect(evt, arg) ⇒ <code>boolean</code>
|
||||
Use a video file as a film out source on "projector"
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
**Returns**: <code>boolean</code> - Success state
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| evt | <code>object</code> | Original connect event |
|
||||
| arg | <code>object</code> | Arguments from ipc message |
|
||||
|
||||
<a name="module_lib/filmout..FilmOut+onPreExport"></a>
|
||||
|
||||
#### filmOut.onPreExport(evt, arg) ⇒ <code>any</code>
|
||||
Pre-export all frames from video for display.
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
**Returns**: <code>any</code> - UI send call
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| evt | <code>object</code> | IPC event |
|
||||
| arg | <code>object</code> | IPC args |
|
||||
|
||||
<a name="module_lib/filmout..FilmOut+isGifAnimated"></a>
|
||||
|
||||
#### filmOut.isGifAnimated(pathStr) ⇒ <code>boolean</code>
|
||||
Return true if gif is animated, false if it is a still
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
**Returns**: <code>boolean</code> - Whether or not gif is animated
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| pathStr | <code>string</code> | Path to gif to check |
|
||||
|
||||
<a name="module_lib/filmout..FilmOut+stillInfo"></a>
|
||||
|
||||
#### filmOut.stillInfo(pathStr) ⇒ <code>object</code>
|
||||
Return information on a still image using the Jimp module
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
**Returns**: <code>object</code> - Info about still from sharp
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| pathStr | <code>string</code> | Path to gif to check |
|
||||
|
||||
<a name="module_lib/filmout..FilmOut+dirInfo"></a>
|
||||
|
||||
#### filmOut.dirInfo(images) ⇒ <code>object</code>
|
||||
Return information on the first still image found in a
|
||||
directory using the Jimp module.
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
**Returns**: <code>object</code> - Info about first image
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| images | <code>array</code> | List of image paths |
|
||||
|
||||
<a name="module_lib/filmout..FilmOut+dirList"></a>
|
||||
|
||||
#### filmOut.dirList(pathStr) ⇒ <code>array</code>
|
||||
Returns a list of images within a directory, filtered
|
||||
for supported types and sorted.
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
**Returns**: <code>array</code> - Array of image paths
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| pathStr | <code>string</code> | Path to directory |
|
||||
|
||||
<a name="module_lib/filmout..FilmOut+previewFrame"></a>
|
||||
|
||||
#### filmOut.previewFrame(evt, arg)
|
||||
Preview a frame from the selected video.
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| evt | <code>object</code> | Original event |
|
||||
| arg | <code>object</code> | Arguments from message |
|
||||
|
||||
<a name="module_lib/filmout..FilmOut+preview"></a>
|
||||
|
||||
#### filmOut.preview(evt, arg)
|
||||
Open a single frame in a display window to preview filmout.
|
||||
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| evt | <code>object</code> | Original event |
|
||||
| arg | <code>object</code> | Arguments from message |
|
||||
|
||||
<a name="module_lib/filmout..FilmOut+focus"></a>
|
||||
|
||||
#### filmOut.focus()
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
<a name="module_lib/filmout..FilmOut+field"></a>
|
||||
|
||||
#### filmOut.field()
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
<a name="module_lib/filmout..FilmOut+meter"></a>
|
||||
|
||||
#### filmOut.meter()
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
<a name="module_lib/filmout..FilmOut+close"></a>
|
||||
|
||||
#### filmOut.close()
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
||||
<a name="module_lib/filmout..FilmOut+onDisplay"></a>
|
||||
|
||||
#### filmOut.onDisplay()
|
||||
**Kind**: instance method of [<code>FilmOut</code>](#module_lib/filmout..FilmOut)
|
|
@ -0,0 +1,173 @@
|
|||
import type { Server } from 'server';
|
||||
import type { Display } from 'display';
|
||||
import type { Light } from 'light';
|
||||
import type { FFMPEG } from 'ffmpeg';
|
||||
import type { FFPROBE } from 'ffprobe';
|
||||
import type { WebContents, IpcMainEvent } from 'electron';
|
||||
interface FilmOutState {
|
||||
hash: string;
|
||||
frame: number;
|
||||
frames: number;
|
||||
fps: number;
|
||||
seconds: number;
|
||||
still: boolean;
|
||||
path: string;
|
||||
fileName: string;
|
||||
directory: boolean;
|
||||
info: any;
|
||||
dir: boolean;
|
||||
enabled: boolean;
|
||||
files: string[];
|
||||
}
|
||||
/** @module lib/filmout */
|
||||
/**
|
||||
* Class representing all filmout features.
|
||||
*/
|
||||
export declare class FilmOut {
|
||||
private id;
|
||||
private videoExtensions;
|
||||
private stillExtensions;
|
||||
private sequenceExtensions;
|
||||
private gifExtension;
|
||||
state: FilmOutState;
|
||||
private ffmpeg;
|
||||
private ffprobe;
|
||||
private light;
|
||||
private ipc;
|
||||
private ui;
|
||||
private log;
|
||||
display: Display;
|
||||
server: Server;
|
||||
/**
|
||||
* @constructor
|
||||
* Builds FilmOut class with display, ffmpeg, ffprobe, ui and light as internal properties.
|
||||
*
|
||||
* @param {object} display Display object for showing frames
|
||||
* @param {object} ffmpeg FFMPEG wrapper
|
||||
* @param {object} ffprobe FFPROBE wrapper for file info
|
||||
* @param {object} ui Electron ui object
|
||||
* @param {object} light Light device object
|
||||
**/
|
||||
constructor(display: Display, server: Server, ffmpeg: FFMPEG, ffprobe: FFPROBE, ui: WebContents, light: Light);
|
||||
/**
|
||||
* Async function for requiring log, ipcMain and bind events.
|
||||
**/
|
||||
private init;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
private listen;
|
||||
/**
|
||||
* Create a hash of a string.
|
||||
*
|
||||
* @param {string} data Data to produce hash of
|
||||
*/
|
||||
private hash;
|
||||
/**
|
||||
* Sets filmout direction.
|
||||
*
|
||||
* @param {boolean} dir Direction of filmout
|
||||
**/
|
||||
set(dir: boolean): void;
|
||||
/**
|
||||
* Moves filmout a frame at a time.
|
||||
*
|
||||
* @returns {number} Time since start
|
||||
**/
|
||||
move(): Promise<number>;
|
||||
/**
|
||||
* Begin the process of exporting single frames from the video for display.
|
||||
**/
|
||||
start(): Promise<void>;
|
||||
/**
|
||||
* Ends the filmout process and closes the display.
|
||||
**/
|
||||
end(): Promise<void>;
|
||||
/**
|
||||
* Use a video file as a film out source on "projector"
|
||||
*
|
||||
* @param {object} evt Original connect event
|
||||
* @param {object} arg Arguments from ipc message
|
||||
*
|
||||
* @returns {boolean} Success state
|
||||
**/
|
||||
onConnect(evt: IpcMainEvent, arg: any): Promise<boolean>;
|
||||
/**
|
||||
* Pre-export all frames from video for display.
|
||||
*
|
||||
* @param {object} evt IPC event
|
||||
* @param {object} arg IPC args
|
||||
*
|
||||
* @returns {any} UI send call
|
||||
*/
|
||||
onPreExport(evt: IpcMainEvent, arg: any): Promise<any>;
|
||||
/**
|
||||
* Return true if gif is animated, false if it is a still
|
||||
*
|
||||
* @param {string} pathStr Path to gif to check
|
||||
*
|
||||
* @returns {boolean} Whether or not gif is animated
|
||||
**/
|
||||
isGifAnimated(pathStr: string): Promise<boolean>;
|
||||
/**
|
||||
* Return information on a still image using the Jimp module
|
||||
*
|
||||
* @param {string} pathStr Path to gif to check
|
||||
*
|
||||
* @returns {object} Info about still from sharp
|
||||
**/
|
||||
stillInfo(pathStr: string): Promise<any>;
|
||||
/**
|
||||
* Return information on the first still image found in a
|
||||
* directory using the Jimp module.
|
||||
*
|
||||
* @param {array} images List of image paths
|
||||
*
|
||||
* @returns {object} Info about first image
|
||||
**/
|
||||
dirInfo(images: string[]): Promise<any>;
|
||||
/**
|
||||
* Returns a list of images within a directory, filtered
|
||||
* for supported types and sorted.
|
||||
*
|
||||
* @param {string} pathStr Path to directory
|
||||
*
|
||||
* @returns {array} Array of image paths
|
||||
**/
|
||||
dirList(pathStr: string): Promise<string[]>;
|
||||
/**
|
||||
* Preview a frame from the selected video.
|
||||
*
|
||||
* @param {object} evt Original event
|
||||
* @param {object} arg Arguments from message
|
||||
**/
|
||||
previewFrame(evt: IpcMainEvent, arg: any): Promise<void>;
|
||||
/**
|
||||
* Open a single frame in a display window to preview filmout.
|
||||
*
|
||||
* @param {object} evt Original event
|
||||
* @param {object} arg Arguments from message
|
||||
**/
|
||||
preview(evt: IpcMainEvent, arg: any): Promise<void>;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
focus(evt: IpcMainEvent, arg: any): Promise<void>;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
field(evt: IpcMainEvent, arg: any): Promise<void>;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
meter(evt: IpcMainEvent, arg: any): Promise<void>;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
close(evt: IpcMainEvent, arg: any): Promise<void>;
|
||||
/**
|
||||
*
|
||||
**/
|
||||
onDisplay(evt: IpcMainEvent, arg: any): void;
|
||||
}
|
||||
export type { FilmOutState };
|
|
@ -0,0 +1,509 @@
|
|||
'use strict';
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.FilmOut = void 0;
|
||||
const electron_1 = require("electron");
|
||||
const animated_gif_detector_1 = __importDefault(require("animated-gif-detector"));
|
||||
const path_1 = require("path");
|
||||
const fs_extra_1 = require("fs-extra");
|
||||
const delay_1 = require("delay");
|
||||
const crypto_1 = require("crypto");
|
||||
const frame_1 = require("frame");
|
||||
const log_1 = require("log");
|
||||
/** @module lib/filmout */
|
||||
/**
|
||||
* Class representing all filmout features.
|
||||
*/
|
||||
class FilmOut {
|
||||
/**
|
||||
* @constructor
|
||||
* Builds FilmOut class with display, ffmpeg, ffprobe, ui and light as internal properties.
|
||||
*
|
||||
* @param {object} display Display object for showing frames
|
||||
* @param {object} ffmpeg FFMPEG wrapper
|
||||
* @param {object} ffprobe FFPROBE wrapper for file info
|
||||
* @param {object} ui Electron ui object
|
||||
* @param {object} light Light device object
|
||||
**/
|
||||
constructor(display, server, ffmpeg, ffprobe, ui, light) {
|
||||
this.id = 'filmout';
|
||||
this.videoExtensions = ['.mpg', '.mpeg', '.mov', '.mkv', '.avi', '.mp4'];
|
||||
this.stillExtensions = ['.tif', '.tiff', '.png', '.jpg', '.jpeg', '.bmp'];
|
||||
this.sequenceExtensions = ['.png', '.jpg', '.jpeg'];
|
||||
this.gifExtension = '.gif';
|
||||
this.state = {
|
||||
hash: null,
|
||||
frame: 0,
|
||||
frames: 0,
|
||||
fps: 24,
|
||||
seconds: 0,
|
||||
still: false,
|
||||
path: null,
|
||||
fileName: null,
|
||||
directory: false,
|
||||
info: {},
|
||||
dir: true,
|
||||
enabled: false,
|
||||
files: []
|
||||
};
|
||||
this.ipc = electron_1.ipcMain;
|
||||
this.display = display;
|
||||
this.server = server;
|
||||
this.ffmpeg = ffmpeg;
|
||||
this.ffprobe = ffprobe;
|
||||
this.ui = ui;
|
||||
this.light = light;
|
||||
this.init();
|
||||
}
|
||||
/**
|
||||
* Async function for requiring log, ipcMain and bind events.
|
||||
**/
|
||||
async init() {
|
||||
this.log = await (0, log_1.Log)({ label: this.id });
|
||||
this.listen();
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
listen() {
|
||||
this.ipc.on(this.id, this.onConnect.bind(this));
|
||||
this.ipc.on('focus', this.focus.bind(this));
|
||||
this.ipc.on('field', this.field.bind(this));
|
||||
this.ipc.on('meter', this.meter.bind(this));
|
||||
this.ipc.on('filmout_close', this.close.bind(this));
|
||||
this.ipc.on('preview', this.preview.bind(this));
|
||||
this.ipc.on('preview_frame', this.previewFrame.bind(this));
|
||||
this.ipc.on('display', this.onDisplay.bind(this));
|
||||
this.ipc.on('pre_export', this.onPreExport.bind(this));
|
||||
this.ffmpeg.onProgress = (obj) => {
|
||||
this.ui.send('pre_export_progress', { progress: obj });
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Create a hash of a string.
|
||||
*
|
||||
* @param {string} data Data to produce hash of
|
||||
*/
|
||||
hash(data) {
|
||||
return (0, crypto_1.createHash)('sha1').update(data).digest('hex');
|
||||
}
|
||||
/**
|
||||
* Sets filmout direction.
|
||||
*
|
||||
* @param {boolean} dir Direction of filmout
|
||||
**/
|
||||
set(dir) {
|
||||
this.state.dir = dir;
|
||||
}
|
||||
/**
|
||||
* Moves filmout a frame at a time.
|
||||
*
|
||||
* @returns {number} Time since start
|
||||
**/
|
||||
async move() {
|
||||
let start = +new Date();
|
||||
if (this.state.still) {
|
||||
return -1;
|
||||
}
|
||||
if (this.state.dir) {
|
||||
this.state.frame++;
|
||||
}
|
||||
else {
|
||||
this.state.frame--;
|
||||
}
|
||||
if (this.state.frame < 1) {
|
||||
this.state.frame = 1;
|
||||
}
|
||||
return (+new Date()) - start;
|
||||
}
|
||||
/**
|
||||
* Begin the process of exporting single frames from the video for display.
|
||||
**/
|
||||
async start() {
|
||||
let path;
|
||||
try {
|
||||
path = await this.ffmpeg.frame(this.state, this.light.state);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
throw err;
|
||||
}
|
||||
if (this.server.displayImage(path)) {
|
||||
await (0, delay_1.delay)(20);
|
||||
return;
|
||||
}
|
||||
await this.display.show(path);
|
||||
await (0, delay_1.delay)(20);
|
||||
}
|
||||
/**
|
||||
* Ends the filmout process and closes the display.
|
||||
**/
|
||||
async end() {
|
||||
await (0, delay_1.delay)(20);
|
||||
this.display.hide();
|
||||
}
|
||||
/**
|
||||
* Use a video file as a film out source on "projector"
|
||||
*
|
||||
* @param {object} evt Original connect event
|
||||
* @param {object} arg Arguments from ipc message
|
||||
*
|
||||
* @returns {boolean} Success state
|
||||
**/
|
||||
async onConnect(evt, arg) {
|
||||
let frames = 0;
|
||||
let isAnimated = false;
|
||||
let info;
|
||||
let ext;
|
||||
let stats;
|
||||
let frameList;
|
||||
try {
|
||||
stats = await (0, fs_extra_1.lstat)(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
ext = (0, path_1.extname)(arg.fileName.toLowerCase());
|
||||
if (stats.isDirectory()) {
|
||||
this.state.directory = true;
|
||||
this.state.still = false;
|
||||
}
|
||||
else if (ext === this.gifExtension) {
|
||||
try {
|
||||
isAnimated = await this.isGifAnimated(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
this.state.still = !isAnimated;
|
||||
}
|
||||
else if (this.stillExtensions.indexOf(ext) !== -1) {
|
||||
this.state.still = true;
|
||||
this.state.directory = false;
|
||||
}
|
||||
else if (this.videoExtensions.indexOf(ext) !== -1) {
|
||||
this.state.still = false;
|
||||
this.state.directory = false;
|
||||
}
|
||||
else {
|
||||
this.log.error(`File is not of a valid file type`, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
await this.ffmpeg.clearAll();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
throw err;
|
||||
}
|
||||
if (this.state.directory) {
|
||||
try {
|
||||
frameList = await this.dirList(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
info = await this.dirInfo(frameList);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
frames = frameList.length;
|
||||
this.state.files = frameList;
|
||||
}
|
||||
else if (this.state.still) {
|
||||
try {
|
||||
info = await this.stillInfo(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
frames = 1;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
info = await this.ffprobe.info(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
frames = await this.ffprobe.frames(arg.path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
this.state.enabled = false;
|
||||
await this.ui.send(this.id, { valid: false });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this.state.frame = 0;
|
||||
this.state.path = arg.path;
|
||||
this.state.fileName = arg.fileName;
|
||||
this.state.frames = frames;
|
||||
this.state.info = info;
|
||||
this.state.hash = this.hash(arg.path);
|
||||
if (info.fps) {
|
||||
this.state.fps = info.fps;
|
||||
}
|
||||
else {
|
||||
this.state.fps = 24; //default
|
||||
}
|
||||
if (info.seconds) {
|
||||
this.state.seconds = info.seconds;
|
||||
}
|
||||
else if (info.fps && frames) {
|
||||
this.state.seconds = frames / info.fps;
|
||||
}
|
||||
else if (this.state.directory) {
|
||||
this.state.seconds = frames / 24;
|
||||
}
|
||||
this.log.info(`Opened ${this.state.fileName}`, 'FILMOUT', true, true);
|
||||
this.log.info(`Frames : ${frames}`, 'FILMOUT', true, true);
|
||||
this.state.enabled = true;
|
||||
await this.ui.send(this.id, { valid: true, state: JSON.stringify(this.state) });
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Pre-export all frames from video for display.
|
||||
*
|
||||
* @param {object} evt IPC event
|
||||
* @param {object} arg IPC args
|
||||
*
|
||||
* @returns {any} UI send call
|
||||
*/
|
||||
async onPreExport(evt, arg) {
|
||||
if (!this.state.path) {
|
||||
return await this.ui.send('pre_export', { complete: false, err: 'No file to pre export.' });
|
||||
}
|
||||
try {
|
||||
await this.ffmpeg.frames(this.state);
|
||||
}
|
||||
catch (err) {
|
||||
return await this.ui.send('pre_export', { complete: false, err });
|
||||
}
|
||||
return await this.ui.send('pre_export', { complete: true });
|
||||
}
|
||||
/**
|
||||
* Return true if gif is animated, false if it is a still
|
||||
*
|
||||
* @param {string} pathStr Path to gif to check
|
||||
*
|
||||
* @returns {boolean} Whether or not gif is animated
|
||||
**/
|
||||
async isGifAnimated(pathStr) {
|
||||
let gifBuffer;
|
||||
try {
|
||||
gifBuffer = await (0, fs_extra_1.readFile)(pathStr);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
return false;
|
||||
}
|
||||
return (0, animated_gif_detector_1.default)(gifBuffer);
|
||||
}
|
||||
/**
|
||||
* Return information on a still image using the Jimp module
|
||||
*
|
||||
* @param {string} pathStr Path to gif to check
|
||||
*
|
||||
* @returns {object} Info about still from sharp
|
||||
**/
|
||||
async stillInfo(pathStr) {
|
||||
let info;
|
||||
try {
|
||||
info = await frame_1.Frame.info(pathStr);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
/**
|
||||
* Return information on the first still image found in a
|
||||
* directory using the Jimp module.
|
||||
*
|
||||
* @param {array} images List of image paths
|
||||
*
|
||||
* @returns {object} Info about first image
|
||||
**/
|
||||
async dirInfo(images) {
|
||||
let info;
|
||||
try {
|
||||
info = await this.stillInfo(images[0]);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
/**
|
||||
* Returns a list of images within a directory, filtered
|
||||
* for supported types and sorted.
|
||||
*
|
||||
* @param {string} pathStr Path to directory
|
||||
*
|
||||
* @returns {array} Array of image paths
|
||||
**/
|
||||
async dirList(pathStr) {
|
||||
let frameList = [];
|
||||
try {
|
||||
frameList = await (0, fs_extra_1.readdir)(pathStr);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
frameList = frameList.filter((fileName) => {
|
||||
let ext = (0, path_1.extname)(fileName);
|
||||
if (this.sequenceExtensions.indexOf(ext) !== -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
frameList.sort();
|
||||
frameList = frameList.map((fileName) => {
|
||||
return (0, path_1.join)(pathStr, fileName);
|
||||
});
|
||||
return frameList;
|
||||
}
|
||||
/**
|
||||
* Preview a frame from the selected video.
|
||||
*
|
||||
* @param {object} evt Original event
|
||||
* @param {object} arg Arguments from message
|
||||
**/
|
||||
async previewFrame(evt, arg) {
|
||||
const state = JSON.parse(JSON.stringify(this.state));
|
||||
let path;
|
||||
state.frame = arg.frame;
|
||||
try {
|
||||
path = await this.ffmpeg.frame(state, { color: [255, 255, 255] });
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
throw err;
|
||||
}
|
||||
this.ui.send('preview_frame', { path, frame: arg.frame });
|
||||
}
|
||||
/**
|
||||
* Open a single frame in a display window to preview filmout.
|
||||
*
|
||||
* @param {object} evt Original event
|
||||
* @param {object} arg Arguments from message
|
||||
**/
|
||||
async preview(evt, arg) {
|
||||
const state = JSON.parse(JSON.stringify(this.state));
|
||||
let path;
|
||||
state.frame = arg.frame;
|
||||
this.log.info(`Previewing frame ${state.frame} of ${state.fileName}`);
|
||||
try {
|
||||
path = await this.ffmpeg.frame(state, { color: [255, 255, 255] });
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
throw err;
|
||||
}
|
||||
try {
|
||||
if (await this.server.displayImage(path)) {
|
||||
return;
|
||||
}
|
||||
await this.display.open();
|
||||
await this.display.show(path);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async focus(evt, arg) {
|
||||
this.log.info(`Showing focus screen`);
|
||||
try {
|
||||
if (await this.server.cmdAll('focus')) {
|
||||
return;
|
||||
}
|
||||
await this.display.open();
|
||||
await this.display.focus();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async field(evt, arg) {
|
||||
const ratio = arg.ratio;
|
||||
this.log.info(`Showing field guide screen`);
|
||||
try {
|
||||
if (await this.server.cmdAll('field', { ratio })) {
|
||||
return;
|
||||
}
|
||||
await this.display.open();
|
||||
await this.display.field(ratio);
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async meter(evt, arg) {
|
||||
this.log.info(`Showing meter screen`);
|
||||
try {
|
||||
if (await this.server.cmdAll('meter')) {
|
||||
return;
|
||||
}
|
||||
await this.display.open();
|
||||
await this.display.meter();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
async close(evt, arg) {
|
||||
try {
|
||||
if (await this.server.cmdAll('blank')) {
|
||||
return;
|
||||
}
|
||||
await this.display.hide();
|
||||
await this.display.close();
|
||||
}
|
||||
catch (err) {
|
||||
this.log.error(err, 'FILMOUT', true, true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
**/
|
||||
onDisplay(evt, arg) {
|
||||
this.display.change(arg.display);
|
||||
this.log.info(`Changing the display to ${arg.display}`);
|
||||
}
|
||||
}
|
||||
exports.FilmOut = FilmOut;
|
||||
module.exports = { FilmOut };
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "digital",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<a name="module_lib/frame"></a>
|
||||
|
||||
## lib/frame
|
||||
<a name="module_lib/frame..Frame"></a>
|
||||
|
||||
### lib/frame~Frame
|
||||
Class representing the static Frame module.
|
||||
|
||||
**Kind**: inner class of [<code>lib/frame</code>](#module_lib/frame)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue