Compare commits
1789 commits
v0.50.2-rc
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
d14c9141db | ||
|
06c350c4db | ||
|
c3a9d9d002 | ||
|
aeada6dc74 | ||
|
6ba985fd28 | ||
|
2a0bc85738 | ||
|
523ea284a2 | ||
|
a66d7534c2 | ||
|
89ec07622f | ||
|
7e6ad31392 | ||
|
4ab23f03fc | ||
|
29cea5cc07 | ||
|
8dd7150d67 | ||
|
f1b1523017 | ||
|
88ac250fee | ||
|
0a5e9e87ed | ||
|
20413d79b6 | ||
|
ff9011e6ac | ||
|
802139d0a4 | ||
|
68d307fa50 | ||
|
d3900e39b6 | ||
|
35769dede6 | ||
|
ae1e20d131 | ||
|
051af8b6ad | ||
|
5d77b115f9 | ||
|
7dbeeac112 | ||
|
de062c4aee | ||
|
18a3336714 | ||
|
ebf35a1df8 | ||
|
28e168d5e5 | ||
|
7ad66b99e7 | ||
|
7eb7c1a5ff | ||
|
b88e704e6b | ||
|
8d85af8064 | ||
|
f9d7340729 | ||
|
d57300f785 | ||
|
09baf1d9b9 | ||
|
ce692d38ea | ||
|
b1ca3b0183 | ||
|
a4c34d89e2 | ||
|
d7b9ca3391 | ||
|
55a5c7b051 | ||
|
0e2a9a1033 | ||
|
3fd38be789 | ||
|
329d434c83 | ||
|
6a2939d9fc | ||
|
65781e33f7 | ||
|
608721c7ac | ||
|
2846dd926b | ||
|
7a8a16cd9c | ||
|
1c17ff5dd9 | ||
|
b9be8d9f3a | ||
|
6b1069f02a | ||
|
b92fb03856 | ||
|
1a9743e639 | ||
|
2773cbbe6e | ||
|
e11fb5d225 | ||
|
38200b9912 | ||
|
c69826a887 | ||
|
ce4fadbdf9 | ||
|
2895e93323 | ||
|
3859124c05 | ||
|
da5ec6edc1 | ||
|
9825bccf4a | ||
|
f065218ff4 | ||
|
f79c622edf | ||
|
c7ab47f54d | ||
|
8c10617259 | ||
|
2e565fd95b | ||
|
68718f32b2 | ||
|
f70bde0639 | ||
|
2be96a25b1 | ||
|
30cbc3f5c5 | ||
|
8d8c1fd58c | ||
|
d8600e286f | ||
|
7d08800836 | ||
|
27ede86996 | ||
|
60e5471f5e | ||
|
a1e52eea4a | ||
|
5a99d9777f | ||
|
fab69450c0 | ||
|
5609b43fc7 | ||
|
cc9f2e62de | ||
|
dd6a156d7c | ||
|
7b0d38eca7 | ||
|
168ae17eb6 | ||
|
0067d5a411 | ||
|
99ceaadf8b | ||
|
743c75df16 | ||
|
c5b018afc3 | ||
|
c7511fc803 | ||
|
17bd0eec30 | ||
|
5c6f7a391b | ||
|
d841835c9d | ||
|
3c3635977e | ||
|
d69eeaa589 | ||
|
8a9af7d354 | ||
|
6108860063 | ||
|
63ce691b90 | ||
|
de825fd4dc | ||
|
3671e855cb | ||
|
efa682ef02 | ||
|
5319232918 | ||
|
c5b7cc5ac4 | ||
|
02e4b651af | ||
|
34ea712874 | ||
|
562e154675 | ||
|
5b4948891e | ||
|
5ed13de5d6 | ||
|
9e48d22d70 | ||
|
9f40680b64 | ||
|
addcd63794 | ||
|
c11235c70e | ||
|
d8bedba43d | ||
|
befcf9fd55 | ||
|
feb37a17a6 | ||
|
fcff90e78c | ||
|
6acdfc9623 | ||
|
15ad30d509 | ||
|
3980d0f51e | ||
|
43c45c1f62 | ||
|
673ab85bea | ||
|
3932ecf7c0 | ||
|
9386cc678f | ||
|
fe2af64b90 | ||
|
7c2e4eb3e3 | ||
|
0c990ba276 | ||
|
f6fd061dd6 | ||
|
150f280c33 | ||
|
3bd97984c0 | ||
|
c31e40089c | ||
|
465d204e69 | ||
|
6742bc373c | ||
|
75d2464443 | ||
|
6a26771339 | ||
|
5a2e4ae49a | ||
|
0d44213f78 | ||
|
0bb13331d5 | ||
|
6bffc8a993 | ||
|
811bb0cf30 | ||
|
d64da2a8b2 | ||
|
a99f6d4bf2 | ||
|
0101bc0533 | ||
|
83faa7bba0 | ||
|
a18aceed1f | ||
|
2eb0219ad1 | ||
|
c58b3c752e | ||
|
ee98531c00 | ||
|
ee754f0085 | ||
|
3854bf6fd4 | ||
|
3ca62704d5 | ||
|
34d9b05de0 | ||
|
87835451f3 | ||
|
3b7b9e69c7 | ||
|
febbb4f82e | ||
|
e29e982ffb | ||
|
d84746d395 | ||
|
c133d5b53a | ||
|
845f33b4f2 | ||
|
9b26a65be4 | ||
|
2193c61628 | ||
|
aef3eccfbd | ||
|
3034f4ce6c | ||
|
50ae6e2869 | ||
|
21204321c0 | ||
|
daab8a28ed | ||
|
79f05a831f | ||
|
243cd0dffd | ||
|
8e536e7020 | ||
|
b0ab2daf39 | ||
|
3fd3a548ec | ||
|
d1c82c9af0 | ||
|
5ef1baff3b | ||
|
da564452f7 | ||
|
c3d836bca7 | ||
|
745a3ca889 | ||
|
f5564086c4 | ||
|
0e6b2eae8b | ||
|
23d61df410 | ||
|
c28c5219c1 | ||
|
1db943518d | ||
|
9f4ba9041b | ||
|
b47bd7e8b6 | ||
|
ec600bb8c8 | ||
|
f055198b29 | ||
|
e1a66d389f | ||
|
1891107a80 | ||
|
cff40b338c | ||
|
945b4b3992 | ||
|
085929a92e | ||
|
7f83c68d82 | ||
|
e0c2f03c16 | ||
|
12b15a2549 | ||
|
4d75922c8b | ||
|
0de96358bd | ||
|
5a24d6c570 | ||
|
1369fbb064 | ||
|
2aeb419969 | ||
|
474115b398 | ||
|
d09e294797 | ||
|
1bfb843606 | ||
|
d302fbae09 | ||
|
52e15bbc96 | ||
|
e0dc359241 | ||
|
8275ff1228 | ||
|
31d896fb8d | ||
|
0c467ddc8d | ||
|
37dbfcb40a | ||
|
f5b4aba9da | ||
|
21af8f4f28 | ||
|
cde52f4d35 | ||
|
7da8be67fe | ||
|
538aa3b42f | ||
|
fd02bb00b3 | ||
|
d5c79495ab | ||
|
702a3f8eb8 | ||
|
35276d5879 | ||
|
a7e70e4d21 | ||
|
6560ab6c7b | ||
|
66bdd3fc87 | ||
|
c843991378 | ||
|
aa008d8a61 | ||
|
ca1d0e71b7 | ||
|
2ddf0a2cbd | ||
|
64e48c1eef | ||
|
10381ef06a | ||
|
cef9ade10e | ||
|
33e5318a29 | ||
|
8ecdaab6d4 | ||
|
9de2465e21 | ||
|
bef46257bc | ||
|
d410664d9a | ||
|
1f8c9fd24d | ||
|
64a2e908ae | ||
|
40e20dfc1b | ||
|
53425d8fe2 | ||
|
ca748fd16a | ||
|
ea7ed53bfe | ||
|
29c605de86 | ||
|
b56746475b | ||
|
94f64f8d25 | ||
|
04a6c735ac | ||
|
e9502410de | ||
|
bf87ac08db | ||
|
72310710af | ||
|
cce7cd43d8 | ||
|
080eee7d92 | ||
|
3058dbb4a6 | ||
|
b7d685b4ec | ||
|
e1ecf87df7 | ||
|
48c5f58a8e | ||
|
aa40a44ce3 | ||
|
8fb67d5980 | ||
|
67608dfc9c | ||
|
9fc600397c | ||
|
3d85cff0ef | ||
|
97fbc5e598 | ||
|
9375ada72a | ||
|
49c5180820 | ||
|
12097dbbba | ||
|
870992a6e4 | ||
|
eb1b412840 | ||
|
7c7c2aa053 | ||
|
f6961f91fe | ||
|
154b20c6c8 | ||
|
43af7ddc5f | ||
|
a574a5c1de | ||
|
c553ee46f6 | ||
|
71eedd20e1 | ||
|
3a4ff9d35d | ||
|
0106c1c361 | ||
|
830567b6ec | ||
|
8bd38114dd | ||
|
92ed44c0f2 | ||
|
bbea2887f2 | ||
|
ca2c6a6f8f | ||
|
ab87591501 | ||
|
24264a15b0 | ||
|
4f74ecfc47 | ||
|
703d1afc06 | ||
|
629b928c80 | ||
|
9a5f69f0eb | ||
|
fe72dcfc2c | ||
|
fe1a2eac33 | ||
|
2e048dc225 | ||
|
cbc3624664 | ||
|
6b37fd2eae | ||
|
d13397d4dd | ||
|
f370aa8db1 | ||
|
0e134a02d7 | ||
|
acbf262641 | ||
|
54b59dd946 | ||
|
eb9bbd4c2c | ||
|
18b4f09bab | ||
|
98852e7eb4 | ||
|
5fdac4898f | ||
|
618ab5e195 | ||
|
f095081c71 | ||
|
3f0cc0bf2e | ||
|
caf32736b5 | ||
|
0ab1aab4e7 | ||
|
0b41fc041a | ||
|
fe95db15b2 | ||
|
c1a54f9707 | ||
|
f06b3bd877 | ||
|
11eed5c9eb | ||
|
18c3bbe6e3 | ||
|
fc3ddf01b1 | ||
|
ca0cd2ca75 | ||
|
2f1fc941bb | ||
|
528a0f4d6e | ||
|
cff17deb5d | ||
|
bd3126a6b8 | ||
|
4f6befc0ce | ||
|
c7021a08ad | ||
|
ea072febae | ||
|
064d8738dd | ||
|
03f5358a8c | ||
|
4cfc201b20 | ||
|
e5c4a5a1d9 | ||
|
ebe253f814 | ||
|
3450d76295 | ||
|
33949e5dbf | ||
|
85899e7e38 | ||
|
22a302f528 | ||
|
8a7b88f073 | ||
|
78fb559fa2 | ||
|
220021964d | ||
|
34283f7be6 | ||
|
ca799ae4ec | ||
|
3812989c0a | ||
|
7a100ec022 | ||
|
ba2caf4eb2 | ||
|
cedfd3e32c | ||
|
e704f87557 | ||
|
0eab08e3b4 | ||
|
a7659c368b | ||
|
82b9640387 | ||
|
5a69c9f4e9 | ||
|
65ad23be4f | ||
|
a1f4a7f8ec | ||
|
6d04ff6e32 | ||
|
68ecfbb990 | ||
|
73600003b0 | ||
|
08c47a57f1 | ||
|
a3398843c2 | ||
|
4fc050fdad | ||
|
d9d7845d96 | ||
|
500ed82988 | ||
|
851a715025 | ||
|
ee520d89e1 | ||
|
fd8cf9b40d | ||
|
dbc980cab5 | ||
|
c00b9cd434 | ||
|
b2e2e84cc0 | ||
|
dfdd3fc248 | ||
|
2549f5b0ad | ||
|
0600646479 | ||
|
36890601a8 | ||
|
59a188044e | ||
|
ca15faef02 | ||
|
24c516acb0 | ||
|
cb7f2e87cf | ||
|
1b2a6f6651 | ||
|
44fd8349a7 | ||
|
18619cac20 | ||
|
27e8159db9 | ||
|
6312f1eee9 | ||
|
1929089fab | ||
|
ae682a4a33 | ||
|
000a750f19 | ||
|
5e3844390f | ||
|
4c17b3818e | ||
|
a0917908bb | ||
|
05d5e6c05d | ||
|
514bc0a273 | ||
|
f474c014f3 | ||
|
0cd1c6d535 | ||
|
e5072c8681 | ||
|
6fed123253 | ||
|
13a9f5035d | ||
|
474782eeb0 | ||
|
3458fa5e50 | ||
|
6e27100606 | ||
|
d22442a316 | ||
|
28383efbdf | ||
|
d9afaadb27 | ||
|
ec14cc8828 | ||
|
3519be4633 | ||
|
408eb9a347 | ||
|
6ba1fafaa0 | ||
|
5e09de5f94 | ||
|
faa21cb681 | ||
|
79dbcfdafa | ||
|
19b24d3f58 | ||
|
5be27a5e2c | ||
|
797c18fd15 | ||
|
5a1cafc7d3 | ||
|
64a31f1aad | ||
|
d89ef5b928 | ||
|
041127bbce | ||
|
0459148e30 | ||
|
4d01452447 | ||
|
e7572312a8 | ||
|
29b845c3fc | ||
|
26f89b3ec9 | ||
|
e262e44912 | ||
|
7c11f91630 | ||
|
b778c70837 | ||
|
60f2fd65fd | ||
|
0c1b681b44 | ||
|
5fed2d01c0 | ||
|
f79446b1e7 | ||
|
cfd876927f | ||
|
f2da969f72 | ||
|
fea6ca8635 | ||
|
f1de3b193e | ||
|
02ba41e759 | ||
|
d50a74327f | ||
|
7afe2c58b0 | ||
|
30b1562e64 | ||
|
1360e21016 | ||
|
c6322ddb24 | ||
|
ba07cdeaa2 | ||
|
01a0c0ec6f | ||
|
73c4791460 | ||
|
83ce35df1b | ||
|
1f381ffb9b | ||
|
ef2c53f678 | ||
|
e0b82528d2 | ||
|
eaf3826df8 | ||
|
88b9c9decd | ||
|
babf6eaff7 | ||
|
34feee3567 | ||
|
cb97e94c4d | ||
|
eb56f1b486 | ||
|
41edd8317c | ||
|
32988bb7ca | ||
|
5df736dc6b | ||
|
7a2adae09c | ||
|
4c8920339d | ||
|
d15423dc65 | ||
|
6718528847 | ||
|
772bf6fcca | ||
|
82895bbce8 | ||
|
118b411b51 | ||
|
ea14fb1a27 | ||
|
b75a0ae85b | ||
|
0864b9ad89 | ||
|
3556015201 | ||
|
1a0f0b4b16 | ||
|
3015018142 | ||
|
1295e4a1d2 | ||
|
06fe810e92 | ||
|
efef0da03b | ||
|
704f508292 | ||
|
5dabeb558b | ||
|
0ba3d78b27 | ||
|
1dfd5386a7 | ||
|
2c8cf1c51c | ||
|
7d5d7d3c55 | ||
|
b50779f1e5 | ||
|
3784ec9e21 | ||
|
e55cae9496 | ||
|
9cc8ccac4e | ||
|
d20e4ad0e7 | ||
|
c66cfb28b5 | ||
|
73214a94ec | ||
|
b6bb5f05ec | ||
|
32dd7ef952 | ||
|
ab9f70930d | ||
|
fca18c26d3 | ||
|
3a77c7507b | ||
|
9694242989 | ||
|
2d008899b6 | ||
|
34c0f8cd04 | ||
|
390bb6dfa6 | ||
|
9306971620 | ||
|
d405ff5ffb | ||
|
e17e355247 | ||
|
23d7dc7892 | ||
|
98df8b265f | ||
|
11a4524c4c | ||
|
6c3ed54d87 | ||
|
1981f16715 | ||
|
aa766dc8ee | ||
|
5088caef1e | ||
|
ee9f63a161 | ||
|
2c3c0e8f1d | ||
|
4aaa26794b | ||
|
3d7470b01d | ||
|
ffb3f1ac35 | ||
|
8d399d6a2c | ||
|
b8cc60697b | ||
|
620de2e6b7 | ||
|
cafefb2a33 | ||
|
f7cb39c496 | ||
|
8b2c7a2b21 | ||
|
9d48d9924d | ||
|
fc657d98d2 | ||
|
0a89a8a2fa | ||
|
eaa32e4df4 | ||
|
1bb491857e | ||
|
3077c778c3 | ||
|
181f17ce6b | ||
|
31333f5706 | ||
|
aff69888da | ||
|
b455e807bc | ||
|
6b5b2698ce | ||
|
88794761d0 | ||
|
1ddfb11870 | ||
|
e3791aefdc | ||
|
b44be39252 | ||
|
4bc4a965d9 | ||
|
3a644d7bfc | ||
|
401f7fec17 | ||
|
95654955b1 | ||
|
0be3154cbe | ||
|
a04c69f787 | ||
|
256ed6a106 | ||
|
fc2e08c882 | ||
|
905a52ea61 | ||
|
d6e14b84db | ||
|
2ba6023926 | ||
|
5ed9e3e3ae | ||
|
5757eb7036 | ||
|
f7b942fa42 | ||
|
d54976e461 | ||
|
aa0db24d0d | ||
|
1cb0461991 | ||
|
11c9a53872 | ||
|
4f07867f8f | ||
|
a5caf57116 | ||
|
76b16d676e | ||
|
37327185b1 | ||
|
3a511842c1 | ||
|
eb241b3504 | ||
|
8859f46e5c | ||
|
135982e9d0 | ||
|
cb6873843f | ||
|
8b3820fb28 | ||
|
4c72a563da | ||
|
56817d4e69 | ||
|
de6c6f9bfd | ||
|
d3be8726fc | ||
|
dac8d711d1 | ||
|
c71b90cecf | ||
|
2cebdc3113 | ||
|
dd7c56a324 | ||
|
2f4dedfba2 | ||
|
81abae875f | ||
|
819bdea0c6 | ||
|
26f80b0ec5 | ||
|
0984fe8370 | ||
|
87636fc887 | ||
|
fdd2d503d9 | ||
|
25b56ada48 | ||
|
b1d4f119a7 | ||
|
a8149fe9bb | ||
|
b796ab3207 | ||
|
ddc29ac853 | ||
|
3e8172af13 | ||
|
78d0ff9793 | ||
|
3c0750a2a0 | ||
|
085d7ad37a | ||
|
9031d2478b | ||
|
64effb4679 | ||
|
7515ed2704 | ||
|
14c4be87aa | ||
|
af7345b3cd | ||
|
78491e71f6 | ||
|
7f73b51cb9 | ||
|
11ac636b74 | ||
|
0e5f528183 | ||
|
8065f6fd5f | ||
|
db5db28d71 | ||
|
37b85b16c3 | ||
|
dfc631cc37 | ||
|
e624ed8c51 | ||
|
cc76a4a665 | ||
|
3b47edc3b9 | ||
|
b78899d62c | ||
|
f38a15ee0d | ||
|
0e391a3d78 | ||
|
65d7e478ac | ||
|
e23e9e1387 | ||
|
6658217865 | ||
|
8bc8c4bcae | ||
|
5c8878353f | ||
|
de6eb99d41 | ||
|
8a277e767a | ||
|
aefa889ee4 | ||
|
63fd867757 | ||
|
fcea4005eb | ||
|
31523d769a | ||
|
432c40fb0c | ||
|
7303abcda6 | ||
|
eca9b2fcbf | ||
|
0fc9cb9e73 | ||
|
a199432b5c | ||
|
6ca058c3a1 | ||
|
1c59913e7a | ||
|
f251ad999e | ||
|
5d06d4e254 | ||
|
d1c74ec997 | ||
|
91fbd615e2 | ||
|
21ba7840ca | ||
|
65902f6d58 | ||
|
3e6743f3f4 | ||
|
9d1ff4e8ae | ||
|
939d26801a | ||
|
2899ce5f9a | ||
|
20bd9644e9 | ||
|
1e002ac585 | ||
|
b83fe995c5 | ||
|
c2e414971d | ||
|
69def916a8 | ||
|
d5e8f2d18c | ||
|
539cf780d7 | ||
|
30fedf6b45 | ||
|
67d9f3907f | ||
|
40ed8059b7 | ||
|
c2a2068926 | ||
|
43564c8b45 | ||
|
bbcdcfe4c1 | ||
|
579230d135 | ||
|
be725639d3 | ||
|
af4ff29b23 | ||
|
40a82838b6 | ||
|
d112204a5d | ||
|
2277d89f64 | ||
|
f5fb5c87c4 | ||
|
058b8f82ab | ||
|
892ab2a704 | ||
|
03d44f772d | ||
|
868df44d2a | ||
|
2dd50776f6 | ||
|
d4e8acb7e7 | ||
|
b6f1b00f7d | ||
|
33c52be56c | ||
|
e8d8dfa76b | ||
|
f6683d3c49 | ||
|
345d9e76b5 | ||
|
bc0a4bdeea | ||
|
8afab7dbba | ||
|
4259d6fc17 | ||
|
160d8fe4b8 | ||
|
737c06f33d | ||
|
663ae2762f | ||
|
093c427b83 | ||
|
89a0d5e597 | ||
|
c278adc1c6 | ||
|
afb352e3bb | ||
|
23f273356a | ||
|
4ddf75f836 | ||
|
de90d2fda6 | ||
|
d370cc37a8 | ||
|
2a3fa58e11 | ||
|
124aa90525 | ||
|
6a5ea5d3c6 | ||
|
a6ece46be4 | ||
|
a227e6a979 | ||
|
aceb8b89ce | ||
|
f246992615 | ||
|
95278f1da1 | ||
|
f8e9047359 | ||
|
04f3dfbb9f | ||
|
91ef5456de | ||
|
03d56d1445 | ||
|
bf8ab2e9ce | ||
|
804edd3308 | ||
|
0c1554e453 | ||
|
663376e970 | ||
|
a05ccdd44f | ||
|
049fb2878e | ||
|
64cbd4ae8d | ||
|
061e4ddd55 | ||
|
a0f164c945 | ||
|
72cceac943 | ||
|
2cd06fcd00 | ||
|
96582afdd8 | ||
|
be9dca362d | ||
|
a9672a4b5c | ||
|
ce7be7229b | ||
|
7f4c22f130 | ||
|
88f32b2ec7 | ||
|
f3fb413a03 | ||
|
3b94ecaf80 | ||
|
5c5d82ee83 | ||
|
529ad258fe | ||
|
1ac16ee087 | ||
|
ebfd648a88 | ||
|
90c469454a | ||
|
4dfcb4645a | ||
|
d4bab45809 | ||
|
79be67831b | ||
|
bba0630890 | ||
|
b69b01e36b | ||
|
02a39e693b | ||
|
d7344f5047 | ||
|
6637c7b98b | ||
|
c6ad44d1e5 | ||
|
bcbfc54188 | ||
|
86e3e8593a | ||
|
4586fbc34b | ||
|
ee609c654f | ||
|
2510217935 | ||
|
fe2142ba49 | ||
|
64323013cf | ||
|
01f73c4861 | ||
|
1124125578 | ||
|
f2a437aee4 | ||
|
80f06c1a9a | ||
|
8eb61e1aca | ||
|
8b0de28b8a | ||
|
1f5a8c2091 | ||
|
7476c883a2 | ||
|
3d48c9852a | ||
|
a8a437bc54 | ||
|
e8c4fb3b7d | ||
|
3afec516d3 | ||
|
3f765e2d90 | ||
|
277d78868d | ||
|
b256a4396b | ||
|
ef5701bb38 | ||
|
a03d4ca20e | ||
|
6d71e53f44 | ||
|
749862c333 | ||
|
74986a8b3a | ||
|
e899a5de65 | ||
|
03cda16847 | ||
|
d8c2a8f5bf | ||
|
1e933a2e0d | ||
|
0141d699f0 | ||
|
edfb5011d7 | ||
|
a14963892f | ||
|
a515088e0b | ||
|
6f9784a43f | ||
|
4e3b07ede5 | ||
|
d5a330a390 | ||
|
2e3d9cb609 | ||
|
3057f70c1c | ||
|
b43ecd8466 | ||
|
741e8f96cb | ||
|
049a952765 | ||
|
6b82aae735 | ||
|
9505182576 | ||
|
6d5c32ba2e | ||
|
e1223d0d02 | ||
|
1671deb0b2 | ||
|
6e152a4137 | ||
|
9a17878661 | ||
|
b3b4e54975 | ||
|
d3fde729f5 | ||
|
aba9198844 | ||
|
98f7dcd000 | ||
|
0c0448abef | ||
|
379a3fb6b0 | ||
|
690f48b7e1 | ||
|
96ac5a8997 | ||
|
c55179998b | ||
|
2cda3d0a62 | ||
|
f7caeba787 | ||
|
502ab6f6a9 | ||
|
52472f3cfb | ||
|
233477a2fa | ||
|
86711057b8 | ||
|
859ccf5ea9 | ||
|
c539e4e10d | ||
|
99c7b28712 | ||
|
4e0434d586 | ||
|
70f795ac8b | ||
|
17871e78c8 | ||
|
e53181f2f3 | ||
|
04b510d88b | ||
|
3b080012ac | ||
|
7da1d8cdf7 | ||
|
8010b2680a | ||
|
9fed5643ff | ||
|
d17a333fc6 | ||
|
1785009fa1 | ||
|
68697baaf4 | ||
|
9722270403 | ||
|
82a39e6562 | ||
|
6e018c7462 | ||
|
ffe22e1c50 | ||
|
bcb1197dfb | ||
|
f8c568e301 | ||
|
51576a827d | ||
|
6ae732b77b | ||
|
15b076fd20 | ||
|
6fe1923ef5 | ||
|
b9bd164b10 | ||
|
5208be07ab | ||
|
9ec8f56051 | ||
|
57ac473b00 | ||
|
618b9a4d3e | ||
|
882c9ca022 | ||
|
fb03d3a7f9 | ||
|
d7329840ef | ||
|
bd92110d1f | ||
|
b686d902d5 | ||
|
9bbe8b1c63 | ||
|
5d889bef27 | ||
|
7f35f87893 | ||
|
58773ede91 | ||
|
afe4fee3f3 | ||
|
503e5e9b76 | ||
|
bd973289b6 | ||
|
4688b4bf58 | ||
|
5f55603fb2 | ||
|
6e6fd61e90 | ||
|
e1fc5fd6e3 | ||
|
05d358ac0b | ||
|
4a8c08c8bf | ||
|
1421a39518 | ||
|
f81b0f5913 | ||
|
a75ce9818c | ||
|
3f162eb285 | ||
|
c0fbc412ae | ||
|
1d23afc531 | ||
|
8ff3b753ad | ||
|
d36371fd88 | ||
|
afe3f913ae | ||
|
7cf9cba3d6 | ||
|
ee5fa45aed | ||
|
7817c57689 | ||
|
926de0959e | ||
|
0ebb9420ef | ||
|
474da87c11 | ||
|
e9a2f44899 | ||
|
658e9bd1db | ||
|
ff9ca662f2 | ||
|
4731786a3f | ||
|
c2b51127ac | ||
|
cd4c1efd70 | ||
|
445566c915 | ||
|
cc3600631e | ||
|
bfdc2319c4 | ||
|
0cc0e213a5 | ||
|
892a6deeaf | ||
|
68bc4e3b90 | ||
|
76296de079 | ||
|
4937baad20 | ||
|
926d76de07 | ||
|
121dcfdcab | ||
|
5e239f48c9 | ||
|
017ec11737 | ||
|
7312badc18 | ||
|
dcac5ebcc9 | ||
|
fd66e6b9b1 | ||
|
19091f249a | ||
|
9d663b3789 | ||
|
cf905d25d5 | ||
|
dbaa702888 | ||
|
b7cbbd0694 | ||
|
c85e448499 | ||
|
68e4684ccd | ||
|
2c812da785 | ||
|
722f933052 | ||
|
67f956f3a0 | ||
|
45fcf0d518 | ||
|
6d91d1c799 | ||
|
be4c75c047 | ||
|
6db75f8a66 | ||
|
7921c0971e | ||
|
c55978f9d6 | ||
|
4f0c6030e1 | ||
|
cc7d2803bc | ||
|
155309deee | ||
|
6b071bab21 | ||
|
ab2bf481d1 | ||
|
5b4d8065e6 | ||
|
1487b83ac5 | ||
|
4b64c35360 | ||
|
4bcd5942af | ||
|
2a19f9f63c | ||
|
ddb4c051ee | ||
|
76201e5955 | ||
|
8bec365fb4 | ||
|
c146bfcd2d | ||
|
ceb1b91273 | ||
|
8a89645f73 | ||
|
1a1f145d14 | ||
|
f2e583f314 | ||
|
0af1dfe282 | ||
|
60f4cca007 | ||
|
2cb950b6d8 | ||
|
fe35ea3764 | ||
|
67bcc1b1ec | ||
|
ff5ca7398c | ||
|
e3e5c50a13 | ||
|
426042feab | ||
|
a6ad758c71 | ||
|
413b19a7e9 | ||
|
4156e83f57 | ||
|
2d66b8666d | ||
|
f01fb7dd22 | ||
|
1d6101ddd2 | ||
|
34368760de | ||
|
f8796e2950 | ||
|
74659f40a1 | ||
|
7bbb1a436c | ||
|
1f2762af02 | ||
|
26b1c901c8 | ||
|
0214c80544 | ||
|
b34a5068be | ||
|
79e39da47f | ||
|
4c87ec9dcb | ||
|
74e4c09033 | ||
|
c0c65c46f4 | ||
|
d462f96834 | ||
|
37d9cbfbeb | ||
|
9983777f86 | ||
|
7802337655 | ||
|
b5fec393c6 | ||
|
b93caf4ebc | ||
|
9dd065a595 | ||
|
172701aeba | ||
|
95c7d4f935 | ||
|
a9a0bc9462 | ||
|
87ae041472 | ||
|
415a522805 | ||
|
fa1b1737bb | ||
|
0cdf881941 | ||
|
b5e9a3c383 | ||
|
0242fae4f5 | ||
|
c65a554796 | ||
|
cc93ac1a01 | ||
|
baf853c647 | ||
|
9c5c566e3a | ||
|
ba1f7e67e4 | ||
|
e2877cf505 | ||
|
eee7878954 | ||
|
c4639934d1 | ||
|
e09199d331 | ||
|
7537b5ae7b | ||
|
4ff32e0c61 | ||
|
74087d2b86 | ||
|
9889c258e3 | ||
|
6cc3216d62 | ||
|
841733d4f0 | ||
|
46e874e83c | ||
|
d25896d99c | ||
|
b6c21dcb84 | ||
|
edebde5a2e | ||
|
2a69c42e5b | ||
|
b1e8d2d6db | ||
|
ef77a5cd00 | ||
|
71d9b0d973 | ||
|
3f4c601428 | ||
|
19f8b0adac | ||
|
e4d7e4f69d | ||
|
403ea8f6f4 | ||
|
6de16813cb | ||
|
077207e203 | ||
|
f6e648222e | ||
|
8dc18e8fcd | ||
|
8fef6c6160 | ||
|
1e9dabe6e2 | ||
|
aed3e98c79 | ||
|
e3006a0edb | ||
|
20b7b24203 | ||
|
76a6c0441c | ||
|
26e2dc16ec | ||
|
1b6c0e474a | ||
|
5253d528a4 | ||
|
ad3fd5700f | ||
|
0987c6e94f | ||
|
ffad52d5b7 | ||
|
6e402240b0 | ||
|
8597195f86 | ||
|
632ce31a5d | ||
|
7a8d213861 | ||
|
c62c667436 | ||
|
038431f95c | ||
|
ed0387d94a | ||
|
f2cd9f372e | ||
|
d88752c646 | ||
|
15e696c4d6 | ||
|
085ea15247 | ||
|
e920738cd1 | ||
|
78b4fa05b3 | ||
|
7975ccf3e0 | ||
|
713dc69ed7 | ||
|
f3b5079241 | ||
|
c82884cff9 | ||
|
ecb14be871 | ||
|
f4559c1cce | ||
|
8919182c0c | ||
|
86e1cfc3dd | ||
|
083aff2ceb | ||
|
2a291366da | ||
|
032e17cecd | ||
|
c983af927f | ||
|
50c606d916 | ||
|
1994b5da04 | ||
|
fbf105e113 | ||
|
573ed1e88c | ||
|
91b908ad50 | ||
|
6ec95647e7 | ||
|
4fc6b89975 | ||
|
b164a5d1f4 | ||
|
fdca58727c | ||
|
3f1e5303db | ||
|
28e9aea290 | ||
|
1600bb69b9 | ||
|
6b2548cc49 | ||
|
c087d8e0bb | ||
|
6a8d32c9bf | ||
|
f6261611f0 | ||
|
e138673d27 | ||
|
47c41b436d | ||
|
283bbb52fa | ||
|
8674b97be8 | ||
|
245709aa52 | ||
|
7375c106a2 | ||
|
0db4e4ab51 | ||
|
bc2a8ba77d | ||
|
dd4385f243 | ||
|
e4f1d4221b | ||
|
8301244507 | ||
|
27400cbe03 | ||
|
e834a4aa51 | ||
|
8e3aee5813 | ||
|
03a218e288 | ||
|
11b5eb49a0 | ||
|
a21b4c5cf3 | ||
|
68432eef26 | ||
|
73cf52426f | ||
|
1eada066ff | ||
|
e5f32b21c4 | ||
|
08738ffcee | ||
|
c71e4718d0 | ||
|
4bf7c68574 | ||
|
765cef7564 | ||
|
3dc7c35cd7 | ||
|
1f902726fb | ||
|
33ee8ed3b7 | ||
|
3e4206ee69 | ||
|
f6dc48fdc0 | ||
|
ed1671fe2f | ||
|
6fc44720d6 | ||
|
424ba85507 | ||
|
be9640972e | ||
|
90e2a225e4 | ||
|
75a6ea21a5 | ||
|
26e67b375c | ||
|
50875566ad | ||
|
9b03f5a1d0 | ||
|
cc07390ea4 | ||
|
1d021fc8e0 | ||
|
fdfa2f1660 | ||
|
ae2354a0e0 | ||
|
3243ce6e0a | ||
|
6f4ce0a57c | ||
|
1745f08fb8 | ||
|
e03325d0e4 | ||
|
a6c413da5c | ||
|
4fe17363f3 | ||
|
5a04d0fea0 | ||
|
dfc013d423 | ||
|
1fa7533ee3 | ||
|
5120db3f53 | ||
|
f3ed597ff6 | ||
|
abe32e5f5c | ||
|
0bf03c4a35 | ||
|
cc4de44f3d | ||
|
6aea8e38bc | ||
|
77d2ab6a43 | ||
|
7ffd59c169 | ||
|
27aa4e4a22 | ||
|
7bb5df97fd | ||
|
cd32fb71c7 | ||
|
84a2a74c8c | ||
|
47d39b20d3 | ||
|
9c05239b04 | ||
|
1882e78d51 | ||
|
299682a6dc | ||
|
08dd1cbf0b | ||
|
70af46149d | ||
|
9cdfb239c0 | ||
|
e59c67a144 | ||
|
e44b7b929e | ||
|
cb0222981c | ||
|
df8216e9d8 | ||
|
1dd8eeb317 | ||
|
4d28c5d208 | ||
|
504f230d59 | ||
|
ad7db1e939 | ||
|
a13708f4dd | ||
|
08c701ba19 | ||
|
b5ad359e32 | ||
|
ba763a85cd | ||
|
d1a8f28464 | ||
|
73c872501c | ||
|
06e6feaf3b | ||
|
d56b32ff19 | ||
|
60c5d3bf67 | ||
|
6bee1915ec | ||
|
637c01750a | ||
|
b2b88b466e | ||
|
0e589c0401 | ||
|
7c8c43d3a7 | ||
|
6354a77bf1 | ||
|
cc7dcc65f9 | ||
|
9426f6af72 | ||
|
e6addb8c2a | ||
|
a2a1ddb403 | ||
|
08548916df | ||
|
47b594107a | ||
|
d0e865b9ec | ||
|
aa1b9b8b99 | ||
|
4e40488629 | ||
|
eb1ab935c5 | ||
|
d0f241d908 | ||
|
4d4fbe4e9a | ||
|
6d7e92d73b | ||
|
ff059c58fd | ||
|
7aaaf998a8 | ||
|
695343532d | ||
|
484f2830c8 | ||
|
6df622307c | ||
|
2f67ca370e | ||
|
0397617bed | ||
|
d612b86a8c | ||
|
00146bcbb2 | ||
|
bc4f71ed8c | ||
|
7581d914fe | ||
|
aced8fb593 | ||
|
16ef013025 | ||
|
5742e1c2ca | ||
|
4731588a3c | ||
|
e77a986125 | ||
|
3d63ce4666 | ||
|
2f92ce8bb4 | ||
|
f8bdd0704f | ||
|
5ef95846d8 | ||
|
0cf6fe3df5 | ||
|
fba8b89b3b | ||
|
da43ad2831 | ||
|
f1c9aa7907 | ||
|
e6376871d5 | ||
|
c5b3d9aef7 | ||
|
b822ae39e1 | ||
|
052aa87ddd | ||
|
d32af5606b | ||
|
3e13930425 | ||
|
6e5e2b7578 | ||
|
7398120c0c | ||
|
2391f66d90 | ||
|
2009be519e | ||
|
2dbd5d0f00 | ||
|
97202dd7aa | ||
|
b595021a7f | ||
|
c11b73d117 | ||
|
9f18822754 | ||
|
6eca14f140 | ||
|
e9710150ad | ||
|
47d9b4a866 | ||
|
8253f5e0dc | ||
|
b777669a7e | ||
|
0de6be77de | ||
|
f7cf21b661 | ||
|
59a8b9d663 | ||
|
ad1c826f2c | ||
|
4bd5beb2f6 | ||
|
af7b553da3 | ||
|
70a1ed6934 | ||
|
35e4c604ef | ||
|
249f06bd21 | ||
|
cd9337f2d4 | ||
|
e7bed19391 | ||
|
f6641ee045 | ||
|
da8000303b | ||
|
1f16736e5a | ||
|
d97a23b699 | ||
|
e2de9bf9e7 | ||
|
8e2ad8b8ca | ||
|
814acc5b11 | ||
|
0bb9c520ff | ||
|
f390320030 | ||
|
36fe736669 | ||
|
67324aca21 | ||
|
b326ad4ec1 | ||
|
3017155867 | ||
|
3fad222848 | ||
|
a493428247 | ||
|
52cba611b3 | ||
|
06e454e9dc | ||
|
5769a27151 | ||
|
33fb1501b8 | ||
|
14d9b99c7b | ||
|
7175e40d61 | ||
|
26efe9fd45 | ||
|
6761cd2aa6 | ||
|
be879ae90a | ||
|
0ef61fc575 | ||
|
a422e857e3 | ||
|
60384772af | ||
|
ffadae9373 | ||
|
7301184255 | ||
|
98b9ad5681 | ||
|
d346c19738 | ||
|
b045f62eb7 | ||
|
5f83c027be | ||
|
e2b8aae554 | ||
|
9af3380af7 | ||
|
6b2569e5f2 | ||
|
73e8a99c7e | ||
|
05d831b283 | ||
|
1f4746ed89 | ||
|
5d8e3d8b0a | ||
|
d1ee904dab | ||
|
75a78cb65d | ||
|
7919d30871 | ||
|
54b970c69c | ||
|
8d1d2d2cf0 | ||
|
c80b6d3f60 | ||
|
ac71654afb | ||
|
bad050096a | ||
|
1772b188ff | ||
|
59f0c85aca | ||
|
4f6740d1f8 | ||
|
d34ef851d0 | ||
|
50556bba97 | ||
|
fc7edc875b | ||
|
6615f28ae1 | ||
|
033b03e6e4 | ||
|
bb8fb038ca | ||
|
9745d6df3e | ||
|
89576572f5 | ||
|
270049316e | ||
|
434030e007 | ||
|
8a5230ed6a | ||
|
bec50829c1 | ||
|
10c04a7991 | ||
|
22d9495b8d | ||
|
5e97fdfa0d | ||
|
041f420416 | ||
|
c84d820b09 | ||
|
49046c9d25 | ||
|
608a421ce5 | ||
|
9c8c00a21f | ||
|
e9868e37a1 | ||
|
ad202d6471 | ||
|
2e0f8c6120 | ||
|
b5b0459aff | ||
|
da23a5625b | ||
|
304c0553da | ||
|
5e2a4960fb | ||
|
8ce12f8e60 | ||
|
5766dc34b5 | ||
|
099667a4bb | ||
|
c5a63de33c | ||
|
04108f32d5 | ||
|
8291cdf7a9 | ||
|
312c561529 | ||
|
ab13b23cef | ||
|
d921bf3340 | ||
|
f3c31f55a1 | ||
|
aa8366f21c | ||
|
11fc51467c | ||
|
8e6c98ca5d | ||
|
c71a0f78f4 | ||
|
90918e745e | ||
|
4d19106544 | ||
|
5ee4827fae | ||
|
eed4793799 | ||
|
b17acc0028 | ||
|
a6b2f91e33 | ||
|
e367b66a08 | ||
|
c44beaf8fa | ||
|
4d638bcf10 | ||
|
3322b91c5d | ||
|
4562a33926 | ||
|
163a10602c | ||
|
aaffd3b089 | ||
|
60afbaf873 | ||
|
3539031e5a | ||
|
73e84b58e7 | ||
|
5a467af1f0 | ||
|
1785520697 | ||
|
2bfc5d7669 | ||
|
852819dd00 | ||
|
360f64e71f | ||
|
97762fdd24 | ||
|
aa8b26b5ca | ||
|
36ac9e038d | ||
|
2ba3f05725 | ||
|
6d8fce6011 | ||
|
1b528ea856 | ||
|
0532e759d4 | ||
|
f4d327f1f4 | ||
|
16cfe1c815 | ||
|
d83856c6cf | ||
|
f6176f048d | ||
|
153185ecc5 | ||
|
a2adddc2b8 | ||
|
7631ecb890 | ||
|
d07dded5a7 | ||
|
21cc2bc281 | ||
|
2273b69658 | ||
|
6b32e9785d | ||
|
7bc47dc786 | ||
|
1768b4fde7 | ||
|
2fcc57dbba | ||
|
52f15df5a3 | ||
|
792dbaba5c | ||
|
7d9fe35d18 | ||
|
f6b1c58b03 | ||
|
767c3aa801 | ||
|
244f5ecaa4 | ||
|
3db845b9bf | ||
|
9f9d0a651b | ||
|
f02dcb7fe7 | ||
|
29a1d89fa5 | ||
|
98593a15f6 | ||
|
13c2c8a9ab | ||
|
3a0ac6335d | ||
|
fbcb740dc9 | ||
|
337cfd8769 | ||
|
60780db94b | ||
|
b4b45ffbdc | ||
|
510056a479 | ||
|
d36c8748e3 | ||
|
d6ac2c7954 | ||
|
95fa01a952 | ||
|
42a9024ab8 | ||
|
1a30cb6586 | ||
|
d0b6839755 | ||
|
2268ab01fb | ||
|
701ec0a473 | ||
|
aea22d10ee | ||
|
03e921e6df | ||
|
eb0992879c | ||
|
6cec8303b9 | ||
|
d8b40931f3 | ||
|
72a4ed107b | ||
|
60130ec91e | ||
|
0d41ba59b3 | ||
|
6f2ef41230 | ||
|
8fa55082d5 | ||
|
932a202573 | ||
|
3d83354533 | ||
|
ba5586933d | ||
|
7a852462f9 | ||
|
ff5c28a70f | ||
|
179f16470b | ||
|
7457eebd88 | ||
|
ce6ae9402b | ||
|
761974ca6f | ||
|
c92bcc945f | ||
|
32d2ac2fc9 | ||
|
6629ea6041 | ||
|
d553c1170e | ||
|
3aa7c754aa | ||
|
055811957b | ||
|
3cd2548206 | ||
|
4ef8247985 | ||
|
3a6bddc588 | ||
|
32d624b807 | ||
|
2aaa9f358b | ||
|
524370711c | ||
|
df2c274216 | ||
|
143be541cf | ||
|
79fb020fc8 | ||
|
f91940a8b3 | ||
|
fca900fb9d | ||
|
f149410902 | ||
|
99f41ae53f | ||
|
e40aa84a40 | ||
|
5680b19dc8 | ||
|
cbf0be3f3c | ||
|
c2ff765a60 | ||
|
9eb0d2a87e | ||
|
7483429ee6 | ||
|
141ebcf1cd | ||
|
09aceb6295 | ||
|
eff948f786 | ||
|
e8d352cc4c | ||
|
6f523fe0d8 | ||
|
d55ef7e899 | ||
|
501d1cf5f1 | ||
|
8ee5f06bfd | ||
|
d5f199be66 | ||
|
f258de54b0 | ||
|
9b7c8fd642 | ||
|
78ce17844b | ||
|
fd03679c56 | ||
|
3a58ca1954 | ||
|
47539edcab | ||
|
617ab25f6e | ||
|
812289ac3c | ||
|
8f423c5ffb | ||
|
b82095a341 | ||
|
eb7d4e1eef | ||
|
a0c2f8fa40 | ||
|
7eeb3d3c55 | ||
|
27abc1e9d3 | ||
|
09cfee2fa1 | ||
|
50dd986787 | ||
|
ca116ba010 | ||
|
46d258c439 | ||
|
5eae88b553 | ||
|
05a1f3cdab | ||
|
3abaed0f17 | ||
|
bd8172693c | ||
|
fae90c4ba1 | ||
|
f1bf067ebd | ||
|
272eb90392 | ||
|
eef218a807 | ||
|
72130b19d2 | ||
|
32772c679b | ||
|
78f2307982 | ||
|
42c319702a | ||
|
304bb3a999 | ||
|
9798bf14f4 | ||
|
ab83357fd0 | ||
|
f0cd159235 | ||
|
78d4efd8f3 | ||
|
2e5cfe7a1e | ||
|
b8c5a0ed29 | ||
|
3ce551f106 | ||
|
28a3db28b7 | ||
|
213c336192 | ||
|
f386352be3 | ||
|
22447aa20a | ||
|
417f0a853b | ||
|
a613f28bc8 | ||
|
eb4e80d56b | ||
|
15015dacd7 | ||
|
dec38e1770 | ||
|
b90066b3f5 | ||
|
8da7ddf6e6 | ||
|
eba8de1cda | ||
|
315bbe21b1 | ||
|
d6d1cf58e9 | ||
|
27a9f654d4 | ||
|
fd2f664870 | ||
|
97a4f5fcab | ||
|
6043b6101b | ||
|
67296716d7 | ||
|
4694cadef6 | ||
|
a6e76bab31 | ||
|
1b3fec0452 | ||
|
19055784ff | ||
|
f8e1274c38 | ||
|
06c6018047 | ||
|
112947adc6 | ||
|
82aaf361f1 | ||
|
8050fa24b2 | ||
|
2b70ad667b | ||
|
54b17ee739 | ||
|
3b1397badc | ||
|
b2c2096da5 | ||
|
1008724761 | ||
|
5dc700e3e2 | ||
|
cded632fd2 | ||
|
9e13596104 | ||
|
b101cb304f | ||
|
b4da616176 | ||
|
09d8b38073 | ||
|
2852138c3a | ||
|
200dc66763 | ||
|
c8659cc44b | ||
|
81acb5d895 | ||
|
9c28bc9a83 | ||
|
2dac41e5e5 | ||
|
df03cf1032 | ||
|
31a84828cc | ||
|
2a6df18b72 | ||
|
5a1bf316c7 | ||
|
73f6d207ea | ||
|
e96e1ed7ca | ||
|
6d2e771fd4 | ||
|
8a52bde902 | ||
|
5f5656d982 | ||
|
2c23055c1a | ||
|
354027a5f4 | ||
|
2292f790a0 | ||
|
3131b48c77 | ||
|
c85d7f12c8 | ||
|
e5795baa10 | ||
|
698bd5eef1 | ||
|
2bbdbf4ed8 | ||
|
4dc333de41 | ||
|
ee1825f5f1 | ||
|
420f2c957e | ||
|
645f8ef452 | ||
|
02fdb1e6df | ||
|
5be7d6ab56 | ||
|
355dd8e755 | ||
|
c24c016eb7 | ||
|
de8d139351 | ||
|
c32a95a885 | ||
|
432c1233b6 | ||
|
0b9e8e4e3a | ||
|
46447cefd8 | ||
|
09ee081218 | ||
|
b9a7f9673d | ||
|
ce71393d83 | ||
|
742110c81c | ||
|
0258c2d3c3 | ||
|
ec5e14ca96 | ||
|
c2a766a3e8 | ||
|
8919cba43c | ||
|
6ef42cd121 | ||
|
41380d20df | ||
|
3a884152b1 | ||
|
355bc9296c | ||
|
44195ec239 | ||
|
ded48bcc3d | ||
|
f04267ffc6 | ||
|
3808c61148 | ||
|
b9fc9b6319 | ||
|
cba369a5ce | ||
|
fe86010be5 | ||
|
6b307352d3 | ||
|
d7a589db01 | ||
|
8bf14c4c04 | ||
|
778250aa0e | ||
|
7a19764e29 | ||
|
6ab2878766 | ||
|
870b9e0c27 | ||
|
b819d59674 | ||
|
c2f945ab3c | ||
|
830375cb32 | ||
|
b0996d4d18 | ||
|
f2d83cbf9d | ||
|
807e520b0e | ||
|
b10b79432f | ||
|
03eed6b961 | ||
|
e2db26c595 | ||
|
1e2919531b | ||
|
955f5ac0df | ||
|
364db9dafa | ||
|
1911a5132b | ||
|
d4fa45b257 | ||
|
7531a2c21a | ||
|
0c71059bf0 | ||
|
6d89f0df7e | ||
|
bd62a55608 | ||
|
f5f3bf21ee | ||
|
f3463ebdeb | ||
|
b0193202d1 | ||
|
b5cc0bb42d | ||
|
a3af1ad44d | ||
|
9b82f57006 | ||
|
0653dbde04 | ||
|
5ac9e70304 | ||
|
47d5de1fca | ||
|
e1be0f30bd | ||
|
13b6cc413b | ||
|
2255450599 | ||
|
8493b1e3df | ||
|
cb2c33a35f | ||
|
e5e4a5688f | ||
|
3a09bb18e3 | ||
|
bcbb1c8185 | ||
|
fe885ae6de | ||
|
dad75f76bd | ||
|
762005f217 | ||
|
a4ce82e97f | ||
|
a841fd6206 | ||
|
27b1101d12 | ||
|
0083a29231 | ||
|
1e3a2d34de | ||
|
e5ed71df25 | ||
|
e4c1f107bd | ||
|
6ba97eddb2 | ||
|
1279a6eaaf | ||
|
fdeea30a4a | ||
|
166d2f9049 | ||
|
1b6c217226 | ||
|
9689ef72a1 | ||
|
56cf3464ab | ||
|
4a8ca1a6c9 | ||
|
e4a3e54613 | ||
|
a7cb0e240e | ||
|
fe69ef2c90 | ||
|
9415d9c05d | ||
|
42dcd34d49 | ||
|
2d9fac46a5 | ||
|
942c85c9f1 | ||
|
989126c603 | ||
|
9f3d779cf2 | ||
|
be7ca41235 | ||
|
bb766211f9 | ||
|
27c7a8a31e | ||
|
6853872e9c | ||
|
e9c386678b | ||
|
f94f98e0f3 | ||
|
ca40e0287b | ||
|
7cf5c1f6fe | ||
|
d1e83fcee2 | ||
|
a76f4e4dfe | ||
|
23072f1a46 | ||
|
7c25de1e58 | ||
|
d63cb0dc2d | ||
|
b2630f6f21 | ||
|
9c808e2b5e | ||
|
8e6604cfa6 | ||
|
28260c27d1 | ||
|
5d31dc536c | ||
|
fbff266b28 | ||
|
a23f0cb30f | ||
|
bf24bd3193 | ||
|
3406c2f800 | ||
|
294866fb4b | ||
|
30d5b3006d | ||
|
216d0fefa0 | ||
|
e08b71774c | ||
|
ae980bc142 | ||
|
57dfaab1ea | ||
|
eea3497845 | ||
|
f5125b25c2 | ||
|
47c2d4633d | ||
|
f344096da4 | ||
|
fb839b92ef | ||
|
5bc462927a | ||
|
20a28865fe | ||
|
3bab4feeca | ||
|
b8ec0c9967 | ||
|
4252db91f9 | ||
|
fbd90b8f3e | ||
|
1d74b364e5 | ||
|
6718d87848 | ||
|
6ccbbebad9 | ||
|
6718f153a9 | ||
|
72443d4d2e | ||
|
8111b8d9dc | ||
|
340c883ac7 | ||
|
855ae15a27 | ||
|
5421a64b65 | ||
|
a9cae23d87 | ||
|
2cc049bb83 | ||
|
dc06e2da99 | ||
|
1ee05d1f7f | ||
|
c73ba60ef5 | ||
|
e23a6f3cd6 | ||
|
ac7ba6b4d9 | ||
|
15fea9fe1f | ||
|
e3ea004f67 | ||
|
0d41e6d88d | ||
|
951745d105 | ||
|
d5ba66ca1a | ||
|
aff8cfdf9c | ||
|
56d4a677a5 | ||
|
039264531f | ||
|
f3869ddb78 | ||
|
9d1cf97aef | ||
|
2a31678632 | ||
|
7c83fa662c | ||
|
707ad5d4de | ||
|
a99042b60b | ||
|
822ab329ac | ||
|
51bbda75ee | ||
|
64928213bf | ||
|
84af2dcef0 | ||
|
4a33e4dce5 | ||
|
3e1f6cdf4d | ||
|
3c3fc90b6a | ||
|
14685e11af | ||
|
9468f2b0f2 | ||
|
bfcdbd575f | ||
|
b17ba20fd5 | ||
|
091dbc617e | ||
|
281fad7382 | ||
|
21ad5077f7 | ||
|
3cdeb98ea8 | ||
|
52f068cead | ||
|
81e4730037 | ||
|
45c158f5b4 | ||
|
d58d96b8dd | ||
|
105fe85504 | ||
|
03ef30eb40 | ||
|
650ce42dc0 | ||
|
bb56de1d4f | ||
|
92e55c7d5f | ||
|
51552b0c53 | ||
|
0bbc72c0ba | ||
|
ac18b85c34 | ||
|
991b45d831 | ||
|
f20d48c3dd | ||
|
ddd6a8d191 | ||
|
e1531b03bf | ||
|
f0d0992d20 | ||
|
d279d70770 | ||
|
8ab0bcd545 | ||
|
9cd86be04f | ||
|
e0e277f27d | ||
|
cf0db043f6 | ||
|
4a0aea15a6 | ||
|
2037dfbd03 | ||
|
5ed576f2d5 | ||
|
49dca7d2ab | ||
|
893e67803e | ||
|
5982b61f0d | ||
|
ad10250e16 | ||
|
9e86cab4eb | ||
|
8755c634ad | ||
|
777566f414 | ||
|
713109167c | ||
|
c546589cc5 | ||
|
f691643eb7 | ||
|
6c137fc0fd | ||
|
76a5fe0d83 | ||
|
f091da3c54 | ||
|
7743f08a6a | ||
|
da60104c96 | ||
|
7fdc3d2919 | ||
|
33c325031d | ||
|
cd8b028f8f | ||
|
e70eb3b5bc | ||
|
5d4828514c | ||
|
ba4a29c102 | ||
|
64e8c8e095 | ||
|
d8a5ca082b | ||
|
4269a63f62 | ||
|
a69512372a | ||
|
6761212ce7 | ||
|
81b9b0d801 | ||
|
995f51711f | ||
|
137c268a7b | ||
|
f1466705c0 | ||
|
43965ddf72 | ||
|
a36a8023c7 | ||
|
3b960aa0a0 | ||
|
d362fe0d75 | ||
|
f2e17f8566 | ||
|
a258fcb039 | ||
|
b261763402 | ||
|
ec996d8bf7 | ||
|
a4a714a561 | ||
|
3446b63768 | ||
|
7a327596cd | ||
|
49395a8a05 | ||
|
8ae7247c35 | ||
|
0ec31d3c29 | ||
|
f18ad64527 | ||
|
1e0afd1b86 | ||
|
816bd07570 | ||
|
76ac4c19b9 | ||
|
ca569dc4a7 | ||
|
376df02434 | ||
|
5aaa038d3f | ||
|
6d07d1b672 | ||
|
204f24354f | ||
|
0f24f3fdfd | ||
|
e5fc28821a | ||
|
dcd0528fda | ||
|
3644eed49b | ||
|
fe3eb1e4c6 | ||
|
3aead19b47 | ||
|
874188a973 | ||
|
372c6d0d9f | ||
|
17d0d9f1e0 | ||
|
99ec447bee | ||
|
92e320e384 | ||
|
2ac5ad0201 | ||
|
70575edfb4 | ||
|
da3e3c8404 | ||
|
40035ae4ad | ||
|
73f593ddb3 | ||
|
1ef44ce199 | ||
|
02c0882d90 | ||
|
51a940ed62 | ||
|
d6fac93d12 | ||
|
0da3fbf309 | ||
|
6697c2a9ce | ||
|
5d40a4c9f6 | ||
|
e164fbdeda | ||
|
1aaaf118c5 | ||
|
954966abbb | ||
|
6b8554517c | ||
|
6b3dce0450 | ||
|
ede83f358d | ||
|
59b7975085 | ||
|
945a5365f9 | ||
|
035f04fb3e | ||
|
611b07052c | ||
|
0987876920 | ||
|
63453284dd | ||
|
a8cc4cefb0 | ||
|
39790d800a | ||
|
895f25cc8c | ||
|
3c51e699f6 | ||
|
605d33331b |
991 changed files with 75553 additions and 35717 deletions
110
.env.defaults
110
.env.defaults
|
@ -1,37 +1,29 @@
|
|||
####### .env.default #########
|
||||
|
||||
# Copy this file to .env to make modifications
|
||||
|
||||
# Base config
|
||||
MATOMO_URL=https://analytics.lbry.com/
|
||||
MATOMO_ID=4
|
||||
WEBPACK_WEB_PORT=9090
|
||||
WEBPACK_ELECTRON_PORT=9091
|
||||
WEB_SERVER_PORT=1337
|
||||
LBRY_WEB_API=https://api.lbry.tv
|
||||
|
||||
## APIS
|
||||
LBRY_WEB_API=https://api.na-backend.odysee.com
|
||||
LBRY_WEB_STREAMING_API=https://cdn.lbryplayer.xyz
|
||||
LBRY_WEB_BUFFER_API=https://collector-service.api.lbry.tv/api/v1/events/video
|
||||
COMMENT_SERVER_API=https://comments.lbry.com/api/v2
|
||||
WELCOME_VERSION=1.0
|
||||
COMMENT_SERVER_API=https://comments.odysee.com/api/v2
|
||||
COMMENT_SERVER_NAME=Odysee
|
||||
SEARCH_SERVER_API=https://lighthouse.odysee.com/search
|
||||
SOCKETY_SERVER_API=wss://sockety.odysee.com/ws
|
||||
THUMBNAIL_CDN_URL=https://image-processor.vanwanet.com/optimize/
|
||||
WELCOME_VERSION=1.2
|
||||
|
||||
# Custom Site info
|
||||
DOMAIN=lbry.tv
|
||||
URL=https://lbry.tv
|
||||
THUMBNAIL_CDN_URL=https://image-optimizer.vanwanet.com/?address=
|
||||
# STRIPE
|
||||
# STRIPE_PUBLIC_KEY='pk_test_NoL1JWL7i1ipfhVId5KfDZgo'
|
||||
|
||||
# UI
|
||||
SITE_TITLE=lbry.tv
|
||||
SITE_NAME=lbry.tv
|
||||
SITE_DESCRIPTION=Meet LBRY, an open, free, and community-controlled content wonderland.
|
||||
SITE_HELP_EMAIL=help@lbry.com
|
||||
LOGO_TITLE=lbry.tv
|
||||
SIMPLE_SITE=false
|
||||
SHOW_ADS=true
|
||||
YRBL_HAPPY_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-happy/7aa50a7e5adaf48691935d55e45d697547392929/839d9a
|
||||
YRBL_SAD_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
|
||||
ENABLE_COMMENT_REACTIONS=true
|
||||
ENABLE_FILE_REACTIONS=false
|
||||
ENABLE_CREATOR_REACTIONS=false
|
||||
ENABLE_NO_SOURCE_CLAIMS=false
|
||||
CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS=4
|
||||
# Analytics
|
||||
MATOMO_URL=https://analytics.lbry.com/
|
||||
MATOMO_ID=4
|
||||
|
||||
# OG
|
||||
OG_TITLE_SUFFIX=| lbry.tv
|
||||
|
@ -39,23 +31,79 @@ OG_HOMEPAGE_TITLE=lbry.tv
|
|||
OG_IMAGE_URL=
|
||||
SITE_CANONICAL_URL=https://lbry.tv
|
||||
|
||||
# UI
|
||||
## Custom Site info
|
||||
DOMAIN=lbry.tv
|
||||
URL=https://lbry.tv
|
||||
SITE_TITLE=LBRY
|
||||
SITE_NAME=LBRY
|
||||
SITE_DESCRIPTION=Meet LBRY, an open, free, and community-controlled content wonderland.
|
||||
SITE_HELP_EMAIL=help@lbry.com
|
||||
LOGO_TITLE=LBRY
|
||||
CLOUD_CONNECT_SITE_NAME=Odysee
|
||||
## Social media
|
||||
TWITTER_ACCOUNT=LBRYcom
|
||||
BRANDED_SITE=odysee
|
||||
|
||||
## OLD IMAGE ASSETS
|
||||
#YRBL_HAPPY_IMG_URL=https://player.odysee.com/api/v3/streams/free/yrbl-happy/7aa50a7e5adaf48691935d55e45d697547392929/839d9a
|
||||
#YRBL_SAD_IMG_URL=https://player.odysee.com/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
|
||||
|
||||
# LOCALE
|
||||
DEFAULT_LANGUAGE=en
|
||||
|
||||
# Custom Settings
|
||||
## CUSTOM SETTINGS
|
||||
# Additional settings for below are found in ui/constants/settings and are for
|
||||
# preventing user settings from applying to custom sites without overwriting them.
|
||||
# UNSYNCED_SETTINGS='theme dark_mode_times automatic_dark_mode_enabled'
|
||||
|
||||
## LINKED CONTENT WHITELIST
|
||||
KNOWN_APP_DOMAINS=lbry.tv,lbry.lat,odysee.com
|
||||
|
||||
# Custom Content
|
||||
## CUSTOM CONTENT
|
||||
# If the following is true, copy custom/homepage.example.js to custom/homepage.js and modify
|
||||
CUSTOM_HOMEPAGE=false
|
||||
|
||||
# Add channels to auto-follow on first run
|
||||
AUTO_FOLLOW_CHANNELS=lbry://@lbry#3fda836a92faaceedfe398225fb9b2ee2ed1f01a
|
||||
# Add up to 2 sidebar links:
|
||||
# PINNED_URI_1=@Lbrylatam#2/Integracionesporseguridad#4
|
||||
# PINNED_LABEL_1=LBRY LATAM
|
||||
# PINNED_URI_2=$/discover?t=lbrytvpaidbeta&fee_amount=>0&claim_type=stream&channel_ids=5af39f818f668d8c00943c9326c5201c4fe3c423,cda9c4e92f19d6fe0764524a2012056e06ca2055,760da3ba3dd85830a843beaaed543a89b7a367e7,40c36948f0da072dcba3e4833e90f71e16de78be,e8f68563d242f6ac9784dcbc41dd86c28a9391d6,7236fc5d2783ea7314d9076ae6c8a250e3992d1a,cf7792c2a37d0d76aaaff84aff0b99a8c791429d,8316ac90764fedf3147799b7b81a6575a9cc398e,8627af93c1a1219150f06b698f4b33e6ed2f1c1e,8972a1bd06de5186e5e89292b05aac8aaa817791,c5b0b17838df2f6c31162f64d55f60f34ae8bfc6,f576d5dba905fc179de880c3fe3eb3281ea74f59,97dd77c93c9603cbb2583f3589f7f5a6c92baa43,f399d873e0c37cf24de9569b5f22bbb30a5c6709,dba870d0620d41b2b9a152c961e0c06cf875ccfc,ca1fd651c9d14bf2e5088bb2aa0146ee7aeb2ae0,50ad846a4b1543b847bf3fdafb7b45f6b2f5844c,e09ff5abe9fb44dd0dd0576894a6db60a6211603,7b6f7517f6b816827d076fa0eaad550aa315a4e7,2068452c41d8da3bd68961335da0072a99258a1a,5da63df97c8255ae94a88940695b8471657dd5a1,3645cf2f5d0bdac0523f945be1c3ff60758f7845,4da85b12244839d6368b9290f1619ff9514ab2a8,4ad942982e43326c7700b1b6443049b3cfd82161,55304f219244abf82f684f759cc0c7769242f3b4,8f42e5b592bb7f7a03f4a94a86a41b1236bb099f,e2a014d885a48f5be2dc6409610996337312facb,c18996ca488753f714d36d4654715927c1d7f9c2,ebc4214424cfa683a7046e1f794fea1e44788d84,06b6d6d6a893fb589ec2ded948f5122856921ed5,07e4546674268fc0222b2ca22d31d0549dc217ee,060940e41973d4f7f16d72a2733138e931c35f41,f8d6eccd887c9cebd36b1d42aa349279b7f5c3ed,68098b8426f967b8d04cc566348b5c128823219e,2bfe6cdb24a21bdc1b76fb7c416edd50e9e85945,1f9bb08bfa2259629f4aaa9ed40f97e9a41b6fa1,2f20148495612946675fe1c8ea99171e4d950b81,bc6938fa1e09e840056c2e831abf9664f397c472,2a6194792beac5130641e932b5ac6e5a99b5ca4f,185ba2bd547a5e4a77d29fe6c1484f47db5e058f,29cc7f6081268eaa5b3f2946e0cd0b952a94812c,49389450b1241f5d8f4c8c4271a3eb56bba33965,ffdc62ac2f7549398d3aca9d2119e83d80d588d5,d7a4d2808074b0c55d6b239f69d90e7a4930f943,d58aa4a0b2f6c2504c3abce8de3f1afb71800acc,77ae23dc7eb8a75609881d4548a79e4935a89d37,f79bce8a60fbece671f6265adc39f6469f3b9b8c,051995fdf0af634e4911704057a551e9392e62b1
|
||||
# PINNED_LABEL_2=Paid Beta
|
||||
|
||||
## FEATURES AND LIMITS
|
||||
SIMPLE_SITE=false
|
||||
#BRANDED_SITE
|
||||
|
||||
ENABLE_COMMENT_REACTIONS=true
|
||||
ENABLE_FILE_REACTIONS=true
|
||||
ENABLE_CREATOR_REACTIONS=true
|
||||
ENABLE_NO_SOURCE_CLAIMS=false
|
||||
ENABLE_PREROLL_ADS=false
|
||||
CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS=4
|
||||
CHANNEL_STAKED_LEVEL_LIVESTREAM=5
|
||||
WEB_PUBLISH_SIZE_LIMIT_GB=4
|
||||
LOADING_BAR_COLOR=#2bbb90
|
||||
LIGHTHOUSE_DEFAULT_TYPES=audio,video,text,image,application
|
||||
|
||||
SHOW_ADS=false
|
||||
|
||||
## SIMPLE_SITE REPLACEMENTS
|
||||
ENABLE_MATURE=true
|
||||
ENABLE_UI_NOTIFICATIONS=false
|
||||
|
||||
#ENABLE_LINK_TO_APP=true
|
||||
#FORCE_ANALYTICS=true
|
||||
#ENABLE_ADVANCED_FILTER=true
|
||||
#ENABLE_PAID_CONTENT=true
|
||||
#USE_FOOTER=true
|
||||
#USE_DISCOVER_WHITELIST=false
|
||||
#ENABLE_WILD_WEST=false
|
||||
#FULL_SIDE_LINKS=true
|
||||
#SHOW_TAGS_INTRO=false
|
||||
|
||||
# SEARCH TYPES
|
||||
#VIDEO_ENABLED=true
|
||||
#AUDIO_ENABLED=true
|
||||
#POSTS_ENABLED=true
|
||||
#IMAGES_ENABLED=true
|
||||
#FILES_ENABLED=true
|
||||
#MODELS_ENABLED=true
|
||||
|
||||
BRANDED_SITE=odysee
|
||||
|
|
|
@ -35,13 +35,14 @@
|
|||
"object-curly-spacing": 0,
|
||||
"one-var": 0,
|
||||
"prefer-promise-reject-errors": 0,
|
||||
"promise/param-names": 0,
|
||||
"react/jsx-indent": 0,
|
||||
"react/jsx-no-comment-textnodes": 0,
|
||||
"react-hooks/exhaustive-deps": "warn",
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
"react/no-unescaped-entities": 0,
|
||||
"space-before-function-paren": [
|
||||
"error",
|
||||
"warn",
|
||||
{
|
||||
"anonymous": "never",
|
||||
"named": "never",
|
||||
|
|
25
.flowconfig
25
.flowconfig
|
@ -1,18 +1,14 @@
|
|||
[ignore]
|
||||
.*\.typeface\.json
|
||||
.*/node_modules/findup/.*
|
||||
|
||||
.*/node_modules/react-plastic/.*
|
||||
.*/node_modules/raf-schd/.*
|
||||
.*/node_modules/react-beautiful-dnd/.*
|
||||
.*/node_modules/resolve/test/.*
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
./flow-typed
|
||||
node_modules/lbry-redux/flow-typed/
|
||||
node_modules/lbryinc/flow-typed/
|
||||
|
||||
[untyped]
|
||||
.*/node_modules/lbry-redux
|
||||
.*/node_modules/lbryinc
|
||||
|
||||
[lints]
|
||||
|
||||
|
@ -30,6 +26,7 @@ module.name_mapper='^modal\(.*\)$' -> '<PROJECT_ROOT>/ui/modal\1'
|
|||
module.name_mapper='^app\(.*\)$' -> '<PROJECT_ROOT>/ui/app\1'
|
||||
module.name_mapper='^native\(.*\)$' -> '<PROJECT_ROOT>/ui/native\1'
|
||||
module.name_mapper='^analytics\(.*\)$' -> '<PROJECT_ROOT>/ui/analytics\1'
|
||||
module.name_mapper='^recsys\(.*\)$' -> '<PROJECT_ROOT>/extras/recsys\1'
|
||||
module.name_mapper='^rewards\(.*\)$' -> '<PROJECT_ROOT>/ui/rewards\1'
|
||||
module.name_mapper='^i18n\(.*\)$' -> '<PROJECT_ROOT>/ui/i18n\1'
|
||||
module.name_mapper='^effects\(.*\)$' -> '<PROJECT_ROOT>/ui/effects\1'
|
||||
|
@ -39,5 +36,17 @@ module.name_mapper='^web\/component\(.*\)$' -> '<PROJECT_ROOT>/web/component\1'
|
|||
module.name_mapper='^web\/effects\(.*\)$' -> '<PROJECT_ROOT>/web/effects\1'
|
||||
module.name_mapper='^web\/page\(.*\)$' -> '<PROJECT_ROOT>/web/page\1'
|
||||
module.name_mapper='^homepage\(.*\)$' -> '<PROJECT_ROOT>/ui/util/homepage\1'
|
||||
module.name_mapper='^scss\/component\(.*\)$' -> '<PROJECT_ROOT>/ui/scss/component/\1'
|
||||
|
||||
esproposal.optional_chaining=enable
|
||||
|
||||
; Extensions
|
||||
module.file_ext=.js
|
||||
module.file_ext=.jsx
|
||||
module.file_ext=.json
|
||||
module.file_ext=.css
|
||||
module.file_ext=.scss
|
||||
|
||||
|
||||
|
||||
[strict]
|
||||
|
|
41
.github/PULL_REQUEST_TEMPLATE.md
vendored
41
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -1,14 +1,26 @@
|
|||
## Fixes
|
||||
|
||||
Issue Number:
|
||||
|
||||
<!-- Tip:
|
||||
- Add keywords to directly close the Issue when the PR is merged.
|
||||
- Skip the keyword if the Issue contains multiple items.
|
||||
- https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword
|
||||
-->
|
||||
|
||||
## What is the current behavior?
|
||||
|
||||
## What is the new behavior?
|
||||
|
||||
## Other information
|
||||
|
||||
<!-- If this PR contains a breaking change, please describe the impact and solution strategy for existing applications below. -->
|
||||
|
||||
## PR Checklist
|
||||
|
||||
<!-- For the checkbox formatting to work properly, make sure there are no spaces on either side of the "x" -->
|
||||
|
||||
Please check all that apply to this PR using "x":
|
||||
|
||||
- [ ] I have checked that this PR is not a duplicate of an existing PR (open, closed or merged)
|
||||
- [ ] I have checked that this PR does not introduce a breaking change
|
||||
- [ ] This PR introduces breaking changes and I have provided a detailed explanation below
|
||||
|
||||
## PR Type
|
||||
<details><summary>Toggle...</summary>
|
||||
|
||||
What kind of change does this PR introduce?
|
||||
|
||||
|
@ -19,14 +31,11 @@ What kind of change does this PR introduce?
|
|||
- [ ] Documentation changes
|
||||
- [ ] Other - Please describe:
|
||||
|
||||
## Fixes
|
||||
Please check all that apply to this PR using "x":
|
||||
|
||||
Issue Number:
|
||||
- [ ] I have checked that this PR is not a duplicate of an existing PR (open, closed or merged)
|
||||
- [ ] I added a line describing my change to CHANGELOG.md
|
||||
- [ ] I have checked that this PR does not introduce a breaking change
|
||||
- [ ] This PR introduces breaking changes and I have provided a detailed explanation below
|
||||
|
||||
## What is the current behavior?
|
||||
|
||||
## What is the new behavior?
|
||||
|
||||
## Other information
|
||||
|
||||
<!-- If this PR contains a breaking change, please describe the impact and solution strategy for existing applications below. -->
|
||||
</details>
|
||||
|
|
65
.github/workflows/deploy.yml
vendored
65
.github/workflows/deploy.yml
vendored
|
@ -11,8 +11,9 @@ jobs:
|
|||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Borales/actions-yarn@v2.3.0
|
||||
- uses: actions/checkout@v3
|
||||
- run: corepack enable
|
||||
- run: yarn
|
||||
- run: yarn lint
|
||||
|
||||
build:
|
||||
|
@ -20,23 +21,39 @@ jobs:
|
|||
name: 'build'
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
node-version: [16.x]
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
- windows-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2-beta
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: corepack enable
|
||||
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
if: startsWith(runner.os, 'mac')
|
||||
with:
|
||||
xcode-version: '10.3.0'
|
||||
xcode-version: '13.1.0'
|
||||
# This is gonna be hacky.
|
||||
# Github made us upgrade xcode, which would force an upgrade of electron-builder to fix mac.
|
||||
# But there were bugs with copyfiles / extraFiles that kept seeing duplicates erroring on ln.
|
||||
# A flag USE_HARD_LINKS=false in electron-builder.json was suggested in comments, but that broke windows builds.
|
||||
# So for now we'll install python2 on mac and make sure it can find it.
|
||||
# Remove this after successfully upgrading electron-builder.
|
||||
# HACK part 1
|
||||
- uses: Homebrew/actions/setup-homebrew@master
|
||||
if: startsWith(runner.os, 'mac')
|
||||
# HACK part 2
|
||||
- name: Install Python2
|
||||
if: startsWith(runner.os, 'mac')
|
||||
run: |
|
||||
/bin/bash -c "$(curl -fsSL https://github.com/alfredapp/dependency-scripts/raw/main/scripts/install-python2.sh)"
|
||||
echo "PYTHON_PATH=/usr/local/bin/python" >> $GITHUB_ENV
|
||||
|
||||
- name: Download blockchain headers
|
||||
run: |
|
||||
|
@ -46,18 +63,18 @@ jobs:
|
|||
|
||||
- name: Build
|
||||
run: |
|
||||
yarn global add cross-env
|
||||
yarn
|
||||
yarn dlx cross-env
|
||||
yarn --network-timeout 600000
|
||||
yarn build
|
||||
node ./build/afterSignHook.js
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN_NEW }}
|
||||
NOTARIZATION_USERNAME: ${{ secrets.NOTARIZATION_USERNAME }}
|
||||
NOTARIZATION_PASSWORD: ${{ secrets.NOTARIZATION_PASSWORD }}
|
||||
WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
||||
WIN_CSC_LINK: https://s3.amazonaws.com/files.lbry.io/cert/win-csc-2020-2021-08.p12
|
||||
CSC_LINK: https://s3.amazonaws.com/files.lbry.io/cert/osx-cert.p12
|
||||
|
||||
WIN_CSC_LINK: https://raw.githubusercontent.com/lbryio/lbry-desktop/master/build/cert2023.pfx
|
||||
CSC_LINK: https://s3.amazonaws.com/files.lbry.io/cert/osx-csc-2021-2022.p12
|
||||
|
||||
# UI
|
||||
MATOMO_URL: https://analytics.lbry.com/
|
||||
|
@ -69,8 +86,6 @@ jobs:
|
|||
SITE_TITLE: lbry.tv
|
||||
SITE_NAME: lbry.tv
|
||||
SHOW_ADS: false
|
||||
YRBL_HAPPY_IMG_URL: https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-happy/7aa50a7e5adaf48691935d55e45d697547392929/839d9a
|
||||
YRBL_SAD_IMG_URL: https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
|
||||
ENABLE_COMMENT_REACTIONS: true
|
||||
ENABLE_NO_SOURCE_CLAIMS: false
|
||||
|
||||
|
@ -78,23 +93,35 @@ jobs:
|
|||
KNOWN_APP_DOMAINS: lbry.tv,lbry.lat,odysee.com
|
||||
CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS: 0
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v2.2.4
|
||||
if: |
|
||||
startsWith(runner.os, 'linux')
|
||||
with:
|
||||
name: Linux
|
||||
path: ./dist/electron/*.*
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v2.2.4
|
||||
if: |
|
||||
startsWith(runner.os, 'mac')
|
||||
with:
|
||||
name: macOS
|
||||
path: ./dist/electron/*.*
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v2.2.4
|
||||
if: |
|
||||
github.event.pull_request.head.repo.full_name == github.repository
|
||||
startsWith(runner.os, 'windows')
|
||||
with:
|
||||
name: Windows
|
||||
path: ./dist/electron/*.*
|
||||
- uses: jakejarvis/s3-sync-action@master
|
||||
if: |
|
||||
startsWith(runner.os, 'linux')
|
||||
with:
|
||||
args: --acl public-read --follow-symlinks --exclude '*' --include '*.deb' --include '*.AppImage' --include '*.dmg'
|
||||
env:
|
||||
AWS_S3_BUCKET: ${{ secrets.ARTIFACTS_BUCKET }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.ARTIFACTS_KEY }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.ARTIFACTS_SECRET }}
|
||||
AWS_REGION: 'us-east-1'
|
||||
SOURCE_DIR: 'dist/electron'
|
||||
DEST_DIR: 'app/release'
|
||||
|
|
13
.gitignore
vendored
13
.gitignore
vendored
|
@ -23,9 +23,22 @@ package-lock.json
|
|||
/web/.env.defaults
|
||||
/custom/*
|
||||
/custom/homepages/*
|
||||
/custom/content/*
|
||||
!/custom/content/default.json
|
||||
!/custom/content/test.json
|
||||
!/custom/homepages/.gitkeep
|
||||
!/custom/homepages
|
||||
!/custom/content
|
||||
!/custom/homepage.example.js
|
||||
!/custom/robots.disallowall
|
||||
!/custom/robots.allowall
|
||||
.env
|
||||
!.env.ody
|
||||
.env.desktop
|
||||
.env.lbrytv
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
!.yarn/releases
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
{
|
||||
"linters": {
|
||||
"ui/**/*.{js,jsx,scss,json}": ["prettier --write", "git add"],
|
||||
"web/**/*.{js,jsx,scss,json}": ["prettier --write", "git add"],
|
||||
"ui/**/*.{js,jsx}": ["eslint", "flow focus-check --color always", "git add"],
|
||||
"web/**/*.{js,jsx,scss}": ["eslint", "git add"]
|
||||
"ui/**/*.{js,jsx}": ["eslint", "flow focus-check --color always", "git add"]
|
||||
},
|
||||
"ignore": ["node_modules", "web/dist/**/*", "dist/**/*", "package-lock.json"]
|
||||
"ignore": ["node_modules", "dist/**/*", "package-lock.json"]
|
||||
}
|
||||
|
|
550
.yarn/plugins/@yarnpkg/plugin-version.cjs
vendored
Normal file
550
.yarn/plugins/@yarnpkg/plugin-version.cjs
vendored
Normal file
File diff suppressed because one or more lines are too long
785
.yarn/releases/yarn-3.2.0.cjs
vendored
Executable file
785
.yarn/releases/yarn-3.2.0.cjs
vendored
Executable file
File diff suppressed because one or more lines are too long
0
.yarn/versions/17d7e90d.yml
vendored
Normal file
0
.yarn/versions/17d7e90d.yml
vendored
Normal file
0
.yarn/versions/33178102.yml
vendored
Normal file
0
.yarn/versions/33178102.yml
vendored
Normal file
0
.yarn/versions/35f2125e.yml
vendored
Normal file
0
.yarn/versions/35f2125e.yml
vendored
Normal file
0
.yarn/versions/4f9fb046.yml
vendored
Normal file
0
.yarn/versions/4f9fb046.yml
vendored
Normal file
0
.yarn/versions/5bc94294.yml
vendored
Normal file
0
.yarn/versions/5bc94294.yml
vendored
Normal file
0
.yarn/versions/5f1212ad.yml
vendored
Normal file
0
.yarn/versions/5f1212ad.yml
vendored
Normal file
0
.yarn/versions/5f4cac99.yml
vendored
Normal file
0
.yarn/versions/5f4cac99.yml
vendored
Normal file
0
.yarn/versions/6b35c994.yml
vendored
Normal file
0
.yarn/versions/6b35c994.yml
vendored
Normal file
0
.yarn/versions/6be5ab70.yml
vendored
Normal file
0
.yarn/versions/6be5ab70.yml
vendored
Normal file
0
.yarn/versions/86ac1afd.yml
vendored
Normal file
0
.yarn/versions/86ac1afd.yml
vendored
Normal file
0
.yarn/versions/8e384637.yml
vendored
Normal file
0
.yarn/versions/8e384637.yml
vendored
Normal file
0
.yarn/versions/909c3734.yml
vendored
Normal file
0
.yarn/versions/909c3734.yml
vendored
Normal file
0
.yarn/versions/951a8d12.yml
vendored
Normal file
0
.yarn/versions/951a8d12.yml
vendored
Normal file
0
.yarn/versions/97e7141a.yml
vendored
Normal file
0
.yarn/versions/97e7141a.yml
vendored
Normal file
0
.yarn/versions/ac69bc5f.yml
vendored
Normal file
0
.yarn/versions/ac69bc5f.yml
vendored
Normal file
0
.yarn/versions/c6e2b914.yml
vendored
Normal file
0
.yarn/versions/c6e2b914.yml
vendored
Normal file
0
.yarn/versions/d1a18cef.yml
vendored
Normal file
0
.yarn/versions/d1a18cef.yml
vendored
Normal file
0
.yarn/versions/ec3a9ddf.yml
vendored
Normal file
0
.yarn/versions/ec3a9ddf.yml
vendored
Normal file
0
.yarn/versions/fc1fde84.yml
vendored
Normal file
0
.yarn/versions/fc1fde84.yml
vendored
Normal file
0
.yarn/versions/fc597c00.yml
vendored
Normal file
0
.yarn/versions/fc597c00.yml
vendored
Normal file
7
.yarnrc.yml
Normal file
7
.yarnrc.yml
Normal file
|
@ -0,0 +1,7 @@
|
|||
nodeLinker: node-modules
|
||||
|
||||
plugins:
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-version.cjs
|
||||
spec: "@yarnpkg/plugin-version"
|
||||
|
||||
yarnPath: .yarn/releases/yarn-3.2.0.cjs
|
346
CHANGELOG.md
346
CHANGELOG.md
|
@ -1,9 +1,351 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [0.53.9] - [2023-2-8]
|
||||
|
||||
### Changed
|
||||
- Updated lbrynet to [0.113.0](https://github.com/lbryio/lbry-sdk/releases/tag/v0.113.0)
|
||||
|
||||
## [0.53.8] - [2022-11-17]
|
||||
|
||||
### Fixed
|
||||
- Selecting a large file in publish no longer crashes ([#7736](https://github.com/lbryio/lbry-desktop/pull/7736))
|
||||
- Unfollowing unpublished channels ([#7737](https://github.com/lbryio/lbry-desktop/pull/7737))
|
||||
|
||||
|
||||
### Changed
|
||||
- Updated xcode to 13.1 and hacked a fix for release ([#7736](https://github.com/lbryio/lbry-desktop/pull/7736))
|
||||
|
||||
## [0.53.7] - [2022-11-10]
|
||||
|
||||
### Added
|
||||
- 'Collections' to txo filter _community pr!_ ([#7711](https://github.com/lbryio/lbry-desktop/pull/7711))
|
||||
- Swap comment servers _community pr!_ ([#7670](https://github.com/lbryio/lbry-desktop/pull/7670))
|
||||
|
||||
### Fixed
|
||||
- Thumbnails no longer disable publish ([#7714](https://github.com/lbryio/lbry-desktop/pull/7714))
|
||||
- Publishing posts were empty ([#7715](https://github.com/lbryio/lbry-desktop/pull/7715))
|
||||
- Minor layout fixes _community pr!_ ([#7709](https://github.com/lbryio/lbry-desktop/pull/7709))
|
||||
- Comment section buttons layout ([#7716](https://github.com/lbryio/lbry-desktop/pull/7716))
|
||||
|
||||
### Changed
|
||||
- Removed watchman and its errors ([#7710](https://github.com/lbryio/lbry-desktop/pull/7710))
|
||||
- Updated lbrynet to [0.112.0](https://github.com/lbryio/lbry-sdk/releases/tag/v0.112.0)
|
||||
|
||||
## [0.53.6] - [2022-10-21]
|
||||
|
||||
### Fixed
|
||||
- Make thumbnails optional ([#7690](https://github.com/lbryio/lbry-desktop/pull/7690))
|
||||
- Show downloads newest first ([#7684](https://github.com/lbryio/lbry-desktop/pull/7684))
|
||||
- Only allow images in image uploader ([#7672](https://github.com/lbryio/lbry-desktop/pull/7672))
|
||||
- Fixed bug with csv exports ([#7697](https://github.com/lbryio/lbry-desktop/pull/7697))
|
||||
- Fixed various upload bugs including transcoding ([#7688](https://github.com/lbryio/lbry-desktop/pull/7688))
|
||||
- Fallback for files with no extension ([#7704](https://github.com/lbryio/lbry-desktop/pull/7704))
|
||||
|
||||
### Changed
|
||||
- Upgraded Electron to v17.2.0 ([#7703](https://github.com/lbryio/lbry-desktop/pull/7703))
|
||||
- Upgraded Electron to v17.0.0 ([#7691](https://github.com/lbryio/lbry-desktop/pull/7691))
|
||||
- Updated lbrynet to [0.111.0](https://github.com/lbryio/lbry-sdk/releases/tag/v0.111.0)
|
||||
|
||||
## [0.53.5] - [2022-08-26]
|
||||
|
||||
### Added
|
||||
- Checkbox to disable background wallpaper ([#7630](https://github.com/lbryio/lbry-desktop/pull/7630))
|
||||
- Handle content blocking from hub ([#7665](https://github.com/lbryio/lbry-desktop/pull/7665))
|
||||
|
||||
### Fixed
|
||||
- Better handle decimals liquidating supports ([#7648](https://github.com/lbryio/lbry-desktop/pull/7648))
|
||||
- Better handle cover uploads ([#7647](https://github.com/lbryio/lbry-desktop/pull/7647))
|
||||
- Use default path when first choosing file on windows ([#7625](https://github.com/lbryio/lbry-desktop/pull/7625))
|
||||
- Emoji button hover ([#7620](https://github.com/lbryio/lbry-desktop/pull/7620))
|
||||
- Prevent infinite retries on thumbs ([#7618](https://github.com/lbryio/lbry-desktop/pull/7618))
|
||||
- Double splash/error on app startup ([#7615](https://github.com/lbryio/lbry-desktop/pull/7615))
|
||||
- App updates are now more coherent, also debs work. ([#7502](https://github.com/lbryio/lbry-desktop/pull/7502))
|
||||
- Better handle many channels moderation calls at startup ([#7674](https://github.com/lbryio/lbry-desktop/pull/7674))
|
||||
- Fix mobile floating viewer position ([#7677](https://github.com/lbryio/lbry-desktop/pull/7677))
|
||||
|
||||
### Changed
|
||||
- Upgraded Electron to v15.5.5 ([#7614](https://github.com/lbryio/lbry-desktop/pull/7614))
|
||||
- Upgraded to lbrynet v0.110.0 ([#7680](https://github.com/lbryio/lbry-desktop/pull/7680))
|
||||
|
||||
|
||||
## [0.53.4] - [2022-06-10]
|
||||
|
||||
### Added
|
||||
- Add top in language category for non-english on homepage ([#7585](https://github.com/lbryio/lbry-desktop/pull/7585))
|
||||
- Auto hosting in settings and hosting first run page ([#7598](https://github.com/lbryio/lbry-desktop/pull/7598))
|
||||
|
||||
### Changed
|
||||
- Updated lbry-sdk to [0.107.2](https://github.com/lbryio/lbry-sdk/releases/tag/v0.107.2)
|
||||
|
||||
### Fixed
|
||||
- Better handle empty collections ([#7571](https://github.com/lbryio/lbry-desktop/pull/7571))
|
||||
- Better handle thumbnails in uploads/collections ([#7574](https://github.com/lbryio/lbry-desktop/pull/7574))
|
||||
- Work towards supporting collections of any claim type ([#7578](https://github.com/lbryio/lbry-desktop/pull/7578))
|
||||
- Improve handling of downed custom servers on startup ([#7593](https://github.com/lbryio/lbry-desktop/pull/7593))
|
||||
- Hide watch progress in related if being played ([#7606](https://github.com/lbryio/lbry-desktop/pull/7606))
|
||||
- IPC disk space calls wait for daemon ready; refresh on vis. component load ([#7610](https://github.com/lbryio/lbry-desktop/pull/7610))
|
||||
|
||||
## [0.53.3] - [2022-04-27]
|
||||
|
||||
### Fixed
|
||||
- Reverted lbry.tv changes that broke production login ([#7569](https://github.com/lbryio/lbry-desktop/pull/7569))
|
||||
- Reverted lbry.tv changes that broke login ([#7570](https://github.com/lbryio/lbry-desktop/pull/7570))
|
||||
|
||||
## [0.53.2] - [2022-04-26]
|
||||
|
||||
### Changed
|
||||
- Upgraded Yarn to Berry branch ([#7530](https://github.com/lbryio/lbry-desktop/pull/7530))
|
||||
- Removed some lbrytv references ([#7560](https://github.com/lbryio/lbry-desktop/pull/7560))
|
||||
- Removed some lbrytv player references ([#7552](https://github.com/lbryio/lbry-desktop/pull/7552))
|
||||
|
||||
### Fixed
|
||||
- Repost style issues ([#7559](https://github.com/lbryio/lbry-desktop/pull/7559))
|
||||
- Disappearing sidebar thumbs ([#7556](https://github.com/lbryio/lbry-desktop/pull/7556))
|
||||
- Restore tags sidebar link ([#7555](https://github.com/lbryio/lbry-desktop/pull/7555))
|
||||
- Playlist view link no longer crashes ([#7552](https://github.com/lbryio/lbry-desktop/pull/7552))
|
||||
|
||||
## [0.53.1] - [2022-04-22]
|
||||
|
||||
### Added
|
||||
- Uploads: show placeholder when loading page _community pr!_ ([#7531](https://github.com/lbryio/lbry-desktop/pull/7531))
|
||||
- Sidebar channel search _styles pr_ ([#7542](https://github.com/lbryio/lbry-desktop/pull/7542))
|
||||
- Viewed content progress indicator on thumbnail part 1 ([#7541](https://github.com/lbryio/lbry-desktop/pull/7541))
|
||||
- Viewed content progress indicator on thumbnail part 2 ([#7547](https://github.com/lbryio/lbry-desktop/pull/7547))
|
||||
- Ability to search through publishes ([#7535](https://github.com/lbryio/lbry-desktop/pull/7535))
|
||||
|
||||
### Changed
|
||||
- Large styles revamp following odysee _styles pr_ ([#7542](https://github.com/lbryio/lbry-desktop/pull/7542))
|
||||
|
||||
### Fixed
|
||||
- Fix bad rerender on homepage _styles pr_ ([#7542](https://github.com/lbryio/lbry-desktop/pull/7542))
|
||||
- Fix post-editor preview mode _community pr!_ ([#7532](https://github.com/lbryio/lbry-desktop/pull/7532))
|
||||
- Fix send-tip default tab ([#7533](https://github.com/lbryio/lbry-desktop/pull/7533))
|
||||
|
||||
## [0.52.6] - [2022-04-04]
|
||||
|
||||
### Added
|
||||
- Discover page medium duration filter ([#7506](https://github.com/lbryio/lbry-desktop/pull/7506))
|
||||
- Keep last used collection for Add To ([#7491](https://github.com/lbryio/lbry-desktop/pull/7491))
|
||||
- Disk space functionality on mac / windows ([#7500](https://github.com/lbryio/lbry-desktop/pull/7500))
|
||||
- Enable renaming private collections ([#7519](https://github.com/lbryio/lbry-desktop/pull/7519))
|
||||
|
||||
### Changed
|
||||
- Some upgrade modal improvements ([#7488](https://github.com/lbryio/lbry-desktop/pull/7488))
|
||||
- Updated lbry-sdk to [0.107.1](https://github.com/lbryio/lbry-sdk/releases/tag/v0.107.1)
|
||||
- New YRBL!; facelift for first run ([#7527](https://github.com/lbryio/lbry-desktop/pull/7527))
|
||||
|
||||
### Fixed
|
||||
- Failed comment count increment ([#7510](https://github.com/lbryio/lbry-desktop/pull/7510))
|
||||
- App crash playing media on older windows versions by updating electron ([#7509](https://github.com/lbryio/lbry-desktop/pull/7509))
|
||||
- Local build failures on mac ([#7497](https://github.com/lbryio/lbry-desktop/pull/7497))
|
||||
- Language change now rerenders whole app ([#7504](https://github.com/lbryio/lbry-desktop/pull/7504))
|
||||
- Mac notarization ([#7518](https://github.com/lbryio/lbry-desktop/pull/7518))
|
||||
- Prevent crash when deleting last comment reply ([#7526](https://github.com/lbryio/lbry-desktop/pull/7526))
|
||||
|
||||
## [0.52.5] - [2022-02-25]
|
||||
|
||||
### Fixed
|
||||
|
||||
- New data hosting ux ([#7493](https://github.com/lbryio/lbry-desktop/pull/7493))
|
||||
- Fix markdown guide button ([#7485](https://github.com/lbryio/lbry-desktop/pull/7485))
|
||||
|
||||
## [0.52.4] - [2022-02-15]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed active channel ([#7481](https://github.com/lbryio/lbry-desktop/pull/7481))
|
||||
- Remove extra search button in header ([#7482](https://github.com/lbryio/lbry-desktop/pull/7482))
|
||||
|
||||
## [0.52.3] - [2022-02-15]
|
||||
|
||||
### Fixed
|
||||
- Fixed comment editing and pinning ([#7476](https://github.com/lbryio/lbry-desktop/pull/7476))
|
||||
- Fixed mac header ([#7479](https://github.com/lbryio/lbry-desktop/pull/7479))
|
||||
- Fixed markdown display and lbry url embedding ([#7474](https://github.com/lbryio/lbry-desktop/pull/7474))
|
||||
|
||||
## [0.52.2] - [2022-02-11]
|
||||
|
||||
### Added
|
||||
|
||||
- Reenabled generating thumbs from video ([#7384](https://github.com/lbryio/lbry-desktop/pull/7409))
|
||||
- Brought in playlist drag and drop playlist reordering _odysee team!_ ([#7442](https://github.com/lbryio/lbry-desktop/pull/7442))
|
||||
- Added duration overlays to ClaimPreview component ([#7420](https://github.com/lbryio/lbry-desktop/pull/7420))
|
||||
- Some Horizontal Scroll groundwork from _odysee team!_
|
||||
- Comment Emotes and Stickers and Mentions refactors from _odysee team!_ ([#7435](https://github.com/lbryio/lbry-desktop/pull/7435))
|
||||
- Seek forward and back from _odysee team!_ () ([#7460](https://github.com/lbryio/lbry-desktop/pull/7460))
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgraded Electron to v15 ([#7384](https://github.com/lbryio/lbry-desktop/pull/7384))
|
||||
- Performance improvements in some selectors ([#7370](https://github.com/lbryio/lbry-desktop/pull/7370))
|
||||
- More Header refactoring from _odysee team!_ ([#7441](https://github.com/lbryio/lbry-desktop/pull/7441))
|
||||
- Header refactoring from _odysee team!_ ([#7440](https://github.com/lbryio/lbry-desktop/pull/7440))
|
||||
- Data hosting ui _incomplete_ ([#7438](https://github.com/lbryio/lbry-desktop/pull/7438))
|
||||
- Updated c: control tags from _odysee team!_ ([#7433](https://github.com/lbryio/lbry-desktop/pull/7433))
|
||||
- Nav keycodes (alt+left) no longer navigate while textarea is focused ([#7458](https://github.com/lbryio/lbry-desktop/pull/7458))
|
||||
- Improved comment-server selection ui/ux ([#7455](https://github.com/lbryio/lbry-desktop/pull/7455))
|
||||
- Improved Data Hosting settings ([#7563](https://github.com/lbryio/lbry-desktop/pull/7563))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Several fallout bugs from recent changes
|
||||
|
||||
## [0.52.1]
|
||||
|
||||
### Skipped patch version
|
||||
|
||||
## [0.52.0] - [2021-12-31]
|
||||
|
||||
### Compatibility
|
||||
|
||||
- Mac <= 10.13 (High Sierra) and Ubuntu <= 16 (Xenial) are no longer supported. If you upgrade, you will need to manually build and install your own lbrynet SDK
|
||||
|
||||
### Added
|
||||
|
||||
- Direct replying to notifications _community pr!_ ([#6935](https://github.com/lbryio/lbry-desktop/pull/6935))
|
||||
- Added "Replay" option on autoplay countdown ([#6921](https://github.com/lbryio/lbry-desktop/pull/6921))
|
||||
- Added "Loop" option on Lists ([#6921](https://github.com/lbryio/lbry-desktop/pull/6921))
|
||||
- Added "Shuffle" option on Lists ([#6921](https://github.com/lbryio/lbry-desktop/pull/6921))
|
||||
- Added Play Next/Previous buttons (with shortcuts SHIFT+N/SHIFT+P) ([#6921](https://github.com/lbryio/lbry-desktop/pull/6921))
|
||||
- Separate control for autoplay next on video player ([#6921](https://github.com/lbryio/lbry-desktop/pull/6921))
|
||||
- Channel Mention selection ability while creating a comment ([#7151](https://github.com/lbryio/lbry-desktop/pull/7151))
|
||||
- Disk space setting under Data Hosting ([#7266](https://github.com/lbryio/lbry-desktop/pull/7266))
|
||||
- Paginated 'All Playlists' page ([#7268](https://github.com/lbryio/lbry-desktop/pull/7268))
|
||||
- Expanded playlist ordering tools ([#7305](https://github.com/lbryio/lbry-desktop/pull/7305))
|
||||
- Setting to upgrade to alpha prerelease builds ([#7353](https://github.com/lbryio/lbry-desktop/pull/7353))
|
||||
|
||||
### Changed
|
||||
|
||||
- Changing the supported language from Filipino to Tagalog _community pr!_ ([#6951](https://github.com/lbryio/lbry-desktop/pull/6951))
|
||||
- Don't show countdown to next item in list ([#6921](https://github.com/lbryio/lbry-desktop/pull/6921))
|
||||
- Changed "View List" popup option to link, so can be opened on a new tab ([#6921](https://github.com/lbryio/lbry-desktop/pull/6921))
|
||||
- App reorganized to remove lbry-redux and lbryinc repository dependencies ([#7240](https://github.com/lbryio/lbry-desktop/pull/7240))
|
||||
- Styling cleanup for file reactions ([#7251](https://github.com/lbryio/lbry-desktop/pull/7251))
|
||||
- Change share url to odysee and allow custom share url in settings ([#7258](https://github.com/lbryio/lbry-desktop/pull/7258))
|
||||
- Change Sign in/up to Cloud Connect for Odysee ([#7260](https://github.com/lbryio/lbry-desktop/pull/7260))
|
||||
- Upgraded to lbrynet v0.106.0 ([#7315](https://github.com/lbryio/lbry-desktop/pull/7315))
|
||||
- Upgraded Electron to v11.5.0 ([#7276](https://github.com/lbryio/lbry-desktop/pull/7276))
|
||||
- Cleaner Discover page filters ([#7306](https://github.com/lbryio/lbry-desktop/pull/7306))
|
||||
- Scroll bar styling ([#7314](https://github.com/lbryio/lbry-desktop/pull/7314))
|
||||
- Remove pages for obsolete features like invites, rewards, swap ([#7330](https://github.com/lbryio/lbry-desktop/pull/7330))
|
||||
- Change file repost to modal _community pr!_ ([#7341](https://github.com/lbryio/lbry-desktop/pull/7341))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Clicking on the title of a floating player will take you back to the list ([#6921](https://github.com/lbryio/lbry-desktop/pull/6921))
|
||||
- Fix floating player stopping on markdown or image files ([#7073](https://github.com/lbryio/lbry-desktop/pull/7073))
|
||||
- Fix list thumbnail upload ([#7074](https://github.com/lbryio/lbry-desktop/pull/7074))
|
||||
- Stream Key is now hidden _community pr!_ ([#7127](https://github.com/lbryio/lbry-desktop/pull/7127))
|
||||
- Fix playlist preview thumbnail ([#7178](https://github.com/lbryio/lbry-desktop/pull/7178)
|
||||
- Fixed “Your Account” popup on mobile ([#7172](https://github.com/lbryio/lbry-desktop/pull/7172))
|
||||
- Fix disable-support for comments ([#7245](https://github.com/lbryio/lbry-desktop/pull/7245))
|
||||
- Fix Electron taking over .html files on linux ([#7291](https://github.com/lbryio/lbry-desktop/pull/7291))
|
||||
- Fix floating player play/pause on drag _community pr!_ ([#7339](https://github.com/lbryio/lbry-desktop/pull/7339))
|
||||
- Fix card dropdown menus triggering menu actions _community pr!_ ([#7335](https://github.com/lbryio/lbry-desktop/pull/7335))
|
||||
|
||||
## [0.51.2] - [2021-08-20]
|
||||
|
||||
### Added
|
||||
|
||||
- Show currently active playing item on playlist _community pr!_ ([#6453](https://github.com/lbryio/lbry-desktop/pull/6453))
|
||||
- Add watch later to hover action for last used playlist on popup _community pr!_ ([#6274](https://github.com/lbryio/lbry-desktop/pull/6274))
|
||||
- Add confirmation on comment removal _community pr!_ ([#6563](https://github.com/lbryio/lbry-desktop/pull/6563))
|
||||
- Show on content page if a file is part of a playlist already _community pr!_([#6393](https://github.com/lbryio/lbry-desktop/pull/6393))
|
||||
- Add filtering to playlists ([#6905](https://github.com/lbryio/lbry-desktop/pull/6905))
|
||||
|
||||
### Changed
|
||||
|
||||
- Use Canonical Url for copy link ([#6500](https://github.com/lbryio/lbry-desktop/pull/6500))
|
||||
- Use better icon for copy link ([#6485](https://github.com/lbryio/lbry-desktop/pull/6485))
|
||||
- Comments load paginated ([#6390](https://github.com/lbryio/lbry-desktop/pull/6390))
|
||||
- Improve twitter share _community pr!_ ([#6690](https://github.com/lbryio/lbry-desktop/pull/6690))
|
||||
- Update lighthouse search api _community pr!_ ([#6731](https://github.com/lbryio/lbry-desktop/pull/6731))
|
||||
- Update sockety api _community pr!_ ([#6747](https://github.com/lbryio/lbry-desktop/pull/6747))
|
||||
- Use resolve for OG metadata instead of chainquery _community pr!_ ([#6787](https://github.com/lbryio/lbry-desktop/pull/6787))
|
||||
- Improved clickability of notification links _community pr!_ ([#6711](https://github.com/lbryio/lbry-desktop/pull/6711))
|
||||
|
||||
### Fixed
|
||||
|
||||
- App now supports '#' and ':' for claimId separator ([#6496](https://github.com/lbryio/lbry-desktop/pull/6496))
|
||||
- Fix "exact match" being applied to Recommended ([#6460](https://github.com/lbryio/lbry-desktop/pull/6460))
|
||||
- Fix upload button on creator analytics _community pr!_ ([#6458](https://github.com/lbryio/lbry-desktop/pull/6458))
|
||||
- Prevent sidebar shortcut activation on textarea _community pr!_ ([#6454](https://github.com/lbryio/lbry-desktop/pull/6454))
|
||||
- Improve accessibility and some minor css fixes _community pr!_ ([#6470](https:/github.com/lbryio/lbry-desktop/pull/6470))
|
||||
- Fix drag / drop publish issues for web users _community pr!_ ([#6466](https://github.com/lbryio/lbry-desktop/pull/6466))
|
||||
- Fix yarn copyenv on windows _community pr!_ ([#6702](https://github.com/lbryio/lbry-desktop/pull/6702))
|
||||
- Fix unnecessary livestream api calls in channel page _community pr!_ ([#6652](https://github.com/lbryio/lbry-desktop/pull/6652))
|
||||
- Fix desktop app fails to resolve deep links _community pr!_ ([#6779](https://github.com/lbryio/lbry-desktop/pull/6779))
|
||||
- Fix wrong release date on GoogleVideo metadata _community pr!_ ([#6787](https://github.com/lbryio/lbry-desktop/pull/6787))
|
||||
- Fix markdown line breaking mid word _community pr!_ ([#6805](https://github.com/lbryio/lbry-desktop/pull/6805))
|
||||
- Added \ and = to reserved symbol warning _community pr!_ ([#6733](https://github.com/lbryio/lbry-desktop/pull/6733))
|
||||
- Don't break words in chat + fix text overflow past 3 dot menu _community pr!_ ([#6602](https://github.com/lbryio/lbry-desktop/pull/6602))
|
||||
- Fix embed shows wrong OG metadata _community pr!_ ([#6815](https://github.com/lbryio/lbry-desktop/pull/6815))
|
||||
- Fix OG: "Unparsable data structure - Truncated Unicode character" _community pr!_ ([#6839](https://github.com/lbryio/lbry-desktop/pull/6839))
|
||||
- Fix Paid embed warning overlay redirection button now links to odysee _community pr!_ ([#6819](https://github.com/lbryio/lbry-desktop/pull/6819))
|
||||
- Fix comment section redirection to create channel _community pr!_ ([#6557](https://github.com/lbryio/lbry-desktop/pull/6557))
|
||||
|
||||
## [0.51.1] - [2021-06-26]
|
||||
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
|
||||
### Fixed
|
||||
|
||||
- Enable sign up on desktop ([#6071](https://github.com/lbryio/lbry-desktop/issues/6071))
|
||||
|
||||
## [0.51.0] - [2021-06-26]
|
||||
|
||||
### Added
|
||||
|
||||
- Private and Publishable Playlists ([#6157](https://github.com/lbryio/lbry-desktop/pull/6157))
|
||||
- Channel thumbnails in following side menu ([#6193](https://github.com/lbryio/lbry-desktop/pull/6193))
|
||||
- Web is now PWA app ([#6120](https://github.com/lbryio/lbry-desktop/pull/6120))
|
||||
- Send a tip with your comment ([#5920](https://github.com/lbryio/lbry-desktop/issues/5920))
|
||||
- Search for tags in search dropdown ([#5876](https://github.com/lbryio/lbry-desktop/issues/5876))
|
||||
- Japanese, Afrikaans, Filipino, Thai and Vietnamese language support ([#5684](https://github.com/lbryio/lbry-desktop/issues/5684))
|
||||
- Brazilian-Portuguese language support ([#5900](https://github.com/lbryio/lbry-desktop/issues/5900))
|
||||
- Highlight comments made by content owner _community pr!_ ([#5744](https://github.com/lbryio/lbry-desktop/pull/5744))
|
||||
- Ability to report infringing content directly from the application ([#5808](https://github.com/lbryio/lbry-desktop/pull/5808))
|
||||
- Re-added ability to export wallet transactions ([#5899](https://github.com/lbryio/lbry-desktop/pull/5899))
|
||||
- 24-hour clock setting _community pr!_ ([#5820](https://github.com/lbryio/lbry-desktop/pull/5820))
|
||||
- "Related" (recommendations) section: added option to view more from current creator _community pr!_ ([#5847](https://github.com/lbryio/lbry-desktop/pull/5847))
|
||||
- Wallet: ability to swap cryptocurrency into LBC ([#5654](https://github.com/lbryio/lbry-desktop/pull/5654))
|
||||
- Wallet: ability to send LBC directly to a user through a name or URL search _community pr!_ ([#5990](https://github.com/lbryio/lbry-desktop/pull/5990))
|
||||
- Publish: ability to edit the Release Date field ([#6049](https://github.com/lbryio/lbry-desktop/pull/6049))
|
||||
- Creator Settings: ability to mute specific words in comments ([#5934](https://github.com/lbryio/lbry-desktop/pull/5934))
|
||||
- Creator Settings: ability to disable comments + assign moderators ([#6199](https://github.com/lbryio/lbry-desktop/pull/6199))
|
||||
- Additional options in context-menu _community pr!_ ([#6106](https://github.com/lbryio/lbry-desktop/pull/6106))
|
||||
|
||||
### Changed
|
||||
|
||||
- Keyboard shortcut additions and changes _community pr!_ ([#5717](https://github.com/lbryio/lbry-desktop/pull/5717))
|
||||
- Removed the 10k character-limit when editing _Posts_ ([#5719](https://github.com/lbryio/lbry-desktop/pull/5719))
|
||||
- Improved search functionality (more filters, infinite-scroll, etc.) ([#5742](https://github.com/lbryio/lbry-desktop/pull/5742))
|
||||
- Removed google related section ads ([#6312](https://github.com/lbryio/lbry-desktop/pull/6312))
|
||||
- Debounce and min characters on wunderbar search ([#6319](https://github.com/lbryio/lbry-desktop/pull/6319))
|
||||
- Don't use optimizer for gif thumbnails ([#6320](https://github.com/lbryio/lbry-desktop/pull/6320))
|
||||
- Upgraded [LBRY SDK 0.99.0](https://github.com/lbryio/lbry/releases/tag/v0.99.0)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Lazy-load claim images to improve app responsiveness ([#5795](https://github.com/lbryio/lbry-desktop/issues/5795))
|
||||
- Fix display of upload date and view count on smaller screens ([#5822](https://github.com/lbryio/lbry-desktop/issues/5822))
|
||||
- Autoplay looping to a previous video or itself ([#5711](https://github.com/lbryio/lbry-desktop/pull/5711))
|
||||
- Autoplay not working in mini-player mode ([#5716](https://github.com/lbryio/lbry-desktop/pull/5716))
|
||||
- Edited claim accidentally moved to 'Anonymous' ([#5767](https://github.com/lbryio/lbry-desktop/pull/5767))
|
||||
- Squished "Upload Date" and "View Count" on smaller screens _community pr!_ ([#5823](https://github.com/lbryio/lbry-desktop/pull/5823))
|
||||
- Home and End key not working in search bar ([#5867](https://github.com/lbryio/lbry-desktop/pull/5867))
|
||||
- Unable to buy paid-Images or Posts ([#6114](https://github.com/lbryio/lbry-desktop/pull/6114))
|
||||
|
||||
## [0.50.2] - [2021-04-2]
|
||||
|
||||
### Changed
|
||||
|
||||
- Disable PDFs until security issue is fixed
|
||||
|
||||
## [0.50.1] - [2021-03-18]
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -1,21 +1,19 @@
|
|||
# Contribute to LBRY
|
||||
|
||||
|
||||
**First:** if you're unsure or afraid of anything, just ask or submit the issue or pull request anyways. You won't be yelled at for giving your best effort. The worst that can happen is that you'll be politely asked to change something. We appreciate any sort of contributions, and don't want a wall of rules to get in the way of that.
|
||||
|
||||
However, for those individuals who want a bit more guidance on the best way to contribute to the project, read on. This document will cover what we're looking for. By addressing all the points we're looking for, it raises the chances we can quickly merge or address your contributions.
|
||||
|
||||
|
||||
## TL;DR?
|
||||
|
||||
* [Here](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+no%3Aassignee)
|
||||
- [Here](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+no%3Aassignee)
|
||||
is a list of help wanted issues.
|
||||
* Comment on an issue to let us know if you are going to work on it, don't take an issue that someone reserved less than 3 days ago.
|
||||
* Submit a pull request and get paid in LBC.
|
||||
* Don't hesitate to contact us with any questions or comments.
|
||||
* [Check out this video for a quickstart guide to running and developing the desktop app](https://spee.ch/7da73fc508ffc4ff8b2711e3c3950110430b0c5f/LBRYAppDesign.mp4).
|
||||
- Comment on an issue to let us know if you are going to work on it, don't take an issue that someone reserved less than 3 days ago.
|
||||
- Submit a pull request and get paid in LBC.
|
||||
- Don't hesitate to contact us with any questions or comments.
|
||||
|
||||
## Contents
|
||||
|
||||
- [Choose an Issue](#choose-an-issue)
|
||||
- [Code Overview](#code-overview)
|
||||
- [Libraries](#libraries)
|
||||
|
@ -38,20 +36,20 @@ receives contributions from individuals outside the core team -- such as yoursel
|
|||
|
||||
To make contributing as easy and rewarding as possible, we have instituted the following system:
|
||||
|
||||
* Anyone can view all issues in the system by clicking on the
|
||||
- Anyone can view all issues in the system by clicking on the
|
||||
[Issues](https://github.com/lbryio/lbry-desktop/issues) button at the top of the page. Feel free to
|
||||
add an issue if you think we have missed something (and you might earn some LBC in the process
|
||||
because we do tip people for reporting bugs).
|
||||
* Once on the [Issues](https://github.com/lbryio/lbry-desktop/issues) page, a potential contributor can
|
||||
- Once on the [Issues](https://github.com/lbryio/lbry-desktop/issues) page, a potential contributor can
|
||||
filter issues by the
|
||||
[Help Wanted](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+no%3Aassignee)
|
||||
label to see a curated list of suggested issues with which community members can help.
|
||||
* Every
|
||||
- Every
|
||||
[Help Wanted](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+no%3Aassignee)
|
||||
issue is ranked on a scale from zero to four.
|
||||
|
||||
| Level | Description |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
|
||||
| Level | Description |
|
||||
| ---------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
|
||||
| [**level 0**](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22level%3A+0%22+no%3Aassignee) | Typos and text edits -- a tech-savvy non-programmer can fix these. |
|
||||
| [**level 1**](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22level%3A+1%22+no%3Aassignee) | Programming issues that require little knowledge of how the LBRY app works. |
|
||||
| [**level 2**](https://github.com/lbryio/lbry-desktop/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22level%3A+2%22+no%3Aassignee) | Issues of average difficulty that require the developer to dig into how the app works a little bit. |
|
||||
|
@ -80,7 +78,7 @@ our styling rules and code best practices.
|
|||
|
||||
### Libraries
|
||||
|
||||
This project uses [lbry-redux](https://github.com/lbryio/lbry-redux) and [lbryionc](https://github.com/lbryio/lbryinc) to share Redux and LBRY API specific code with [lbry-android](https://github.com/lbryio/lbry-android) and other LBRY apps. Over time, more Redux code that is suitable to be shared will be moved into lbry-redux. If modifying Redux code, you may be asked to make some of your changes in lbry-redux rather than lbry-desktop. The steps to work with lbry-redux locally can be found [here](https://github.com/lbryio/lbry-redux#local-development).
|
||||
This project uses [lbry-redux](https://github.com/lbryio/lbry-redux) and [lbryionc](https://github.com/lbryio/lbryinc) to share Redux and LBRY API specific code with other LBRY apps. Over time, more Redux code that is suitable to be shared will be moved into lbry-redux. If modifying Redux code, you may be asked to make some of your changes in lbry-redux rather than lbry-desktop. The steps to work with lbry-redux locally can be found [here](https://github.com/lbryio/lbry-redux#local-development).
|
||||
|
||||
### Flow
|
||||
|
||||
|
@ -140,15 +138,15 @@ Editor integrations are available [here](https://prettier.io/docs/en/editors.htm
|
|||
|
||||
There are a few tools integrated to the project that will ease the process of debugging:
|
||||
|
||||
* [Chrome DevTools](https://developer.chrome.com/devtools)
|
||||
* Also available for the main process as a [remote target](chrome://inspect/#devices).
|
||||
* [Electron Devtron](https://electronjs.org/devtron)
|
||||
* [React DevTools](https://github.com/facebook/react-devtools)
|
||||
* [Redux DevTools](https://github.com/gaearon/redux-devtools)
|
||||
- [Chrome DevTools](https://developer.chrome.com/devtools)
|
||||
- Also available for the main process as a [remote target](chrome://inspect/#devices).
|
||||
- [Electron Devtron](https://electronjs.org/devtron)
|
||||
- [React DevTools](https://github.com/facebook/react-devtools)
|
||||
- [Redux DevTools](https://github.com/gaearon/redux-devtools)
|
||||
|
||||
## Submit a Pull Request
|
||||
|
||||
* After deciding what to work on, a potential contributor can
|
||||
- After deciding what to work on, a potential contributor can
|
||||
[fork](https://help.github.com/articles/fork-a-repo/) this repository, make his or her changes,
|
||||
and submit a
|
||||
[pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/). A
|
||||
|
@ -157,12 +155,12 @@ There are a few tools integrated to the project that will ease the process of de
|
|||
manner and, therefore, not begin working on anything reserved (or updated) within the last 3 days.
|
||||
If someone has been officially assigned an issue via GitHub's assignment system, it is also not
|
||||
available. Contributors are encouraged to ask if they have any questions about issue availability.
|
||||
* The [changelog](https://github.com/lbryio/lbry-desktop/blob/master/CHANGELOG.md) should be updated to
|
||||
- The [changelog](https://github.com/lbryio/lbry-desktop/blob/master/CHANGELOG.md) should be updated to
|
||||
include a reference to the fix/change/addition. See previous entries for format.
|
||||
* Once the pull request is visible in the LBRY repo, a LBRY team member will review it and make sure
|
||||
- Once the pull request is visible in the LBRY repo, a LBRY team member will review it and make sure
|
||||
it is up to our standards. At this point, the contributor may have to change his or her code based
|
||||
on our suggestions and comments.
|
||||
* Then, upon a satisfactory review of the code, we will merge it and send the contributor a tip (in
|
||||
- Then, upon a satisfactory review of the code, we will merge it and send the contributor a tip (in
|
||||
LBC) for the contribution.
|
||||
|
||||
We are dedicated to being fair and friendly in this process. In **general**, level 4 issues will be
|
||||
|
@ -191,10 +189,10 @@ will earn you an extra 50 LBC on top of what we would otherwise tip you.
|
|||
|
||||
# Get in Touch
|
||||
|
||||
| Name | Role | Discord | Email |
|
||||
| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------------
|
||||
| [Tom](https://github.com/tzarebczan) | Community manager. He knows more than anyone about the app and all of its flaws. Reach out to him with any questions about how the app works, if a bug has been reported, or if a feature should be requested. | jiggytom | tom@lbry.com |
|
||||
| [Sean](https://github.com/seanyesmunt) | The primary engineer working on the app. Feel free to ask any questions about the code. | sean | sean@lbry.com |
|
||||
| Name | Role | Discord | Email |
|
||||
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------- |
|
||||
| [Tom](https://github.com/tzarebczan) | Community manager. He knows more than anyone about the app and all of its flaws. Reach out to him with any questions about how the app works, if a bug has been reported, or if a feature should be requested. | jiggytom | tom@lbry.com |
|
||||
| [Sean](https://github.com/seanyesmunt) | The primary engineer working on the app. Feel free to ask any questions about the code. | sean | sean@lbry.com |
|
||||
|
||||
Join our Discord [here](https://chat.lbry.com/).
|
||||
|
||||
|
|
92
README.md
92
README.md
|
@ -1,8 +1,8 @@
|
|||
<img width="40%" src="https://miro.medium.com/max/5198/1*bTVuL2THG_0mpwmE-n7Ezg.png" />
|
||||
|
||||
# LBRY App - https://lbry.tv
|
||||
# LBRY App
|
||||
|
||||
This repo contains the UI code that powers the official LBRY desktop app, as well as lbry.tv. The LBRY app is a graphical browser for the decentralized content marketplace provided by the
|
||||
This repo contains the UI code that powers the official LBRY desktop app. The LBRY app is a graphical browser for the decentralized content marketplace provided by the
|
||||
[LBRY](https://lbry.com) protocol. It is essentially the
|
||||
[lbry daemon](https://github.com/lbryio/lbry) bundled with a UI using
|
||||
[Electron](https://electron.atom.io/).
|
||||
|
@ -55,7 +55,7 @@ We provide installers for Windows, macOS (v10.12.4, Sierra, or greater), and Deb
|
|||
| Latest Pre-release | [Download](https://lbry.com/get/lbry.pre.exe) | [Download](https://lbry.com/get/lbry.pre.dmg) | [Download](https://lbry.com/get/lbry.pre.deb) |
|
||||
|
||||
Our [releases page](https://github.com/lbryio/lbry-desktop/releases) also contains the latest
|
||||
release, pre-releases, and past builds.
|
||||
release, pre-releases, and past builds.
|
||||
_Note: If the deb fails to install using the Ubuntu Software Center, install manually via `sudo dpkg -i <path to deb>`. You'll need to run `sudo apt-get install -f` if this is the first time installing it to install dependencies_
|
||||
|
||||
To install from source or make changes to the application, continue to the next section below.
|
||||
|
@ -63,98 +63,35 @@ To install from source or make changes to the application, continue to the next
|
|||
**Community maintained** builds for Arch Linux and Flatpak are available, see below. These installs will need to be updated manually as the in-app update process only supports Debian installs at this time.
|
||||
_Note: If coming from a deb install, the directory structure is different and you'll need to [migrate data](https://lbry.com/faq/backup-data)._
|
||||
|
||||
| | Flatpak | Arch | ARM/ARM64 |
|
||||
| -------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------- |
|
||||
| Latest Release | [FlatHub Page](https://flathub.org/apps/details/io.lbry.lbry-app) | [AUR Package](https://aur.archlinux.org/packages/lbry-app-bin/) | [Build Guide](https://lbry.tv/@LBRYarm:5) |
|
||||
| Maintainers | [@kcSeb](https://keybase.io/kcseb) | [@kcSeb](https://keybase.io/kcseb)/[@TimurKiyivinski](https://github.com/TimurKiyivinski) | [@Madiator2011](https://github.com/kodxana) |
|
||||
| | Flatpak | Arch | Nixpkgs | ARM/ARM64 |
|
||||
| -------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------- |
|
||||
| Latest Release | [FlatHub Page](https://flathub.org/apps/details/io.lbry.lbry-app) | [AUR Package](https://aur.archlinux.org/packages/lbry-desktop-bin/) | [Nixpkgs](https://search.nixos.org/packages?channel=unstable&show=lbry&query=lbry) | [Build Guide](https://lbry.tv/@LBRYarm:5) |
|
||||
| Maintainers | N/A | [@RubenKelevra](https://github.com/RubenKelevra) | [@Enderger](https://github.com/enderger) | [@Madiator2011](https://github.com/kodxana) |
|
||||
|
||||
## Usage
|
||||
|
||||
Double click the installed application to interact with the LBRY network.
|
||||
Start the installed application to interact with the LBRY network.
|
||||
|
||||
## Running from Source
|
||||
|
||||
You can run the web version (lbry.tv), the electron app, or both at the same time.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
- [Git](https://git-scm.com/downloads)
|
||||
- [Node.js](https://nodejs.org/en/download/) (v10 required)
|
||||
- [Node.js](https://nodejs.org/en/download/) (v16 required)
|
||||
- [Corepack](https://nodejs.org/dist/latest-v17.x/docs/api/corepack.html) `npm i -g corepack` (Included in nodejs 14 LTS, 16 LTS and 17)
|
||||
- [Yarn](https://yarnpkg.com/en/docs/install)
|
||||
|
||||
1. Clone (or [fork](https://help.github.com/articles/fork-a-repo/)) this repository: `git clone https://github.com/lbryio/lbry-desktop`
|
||||
2. Change directory into the cloned repository: `cd lbry-desktop`
|
||||
3. Install the dependencies: `yarn`
|
||||
3. If corepack is not enabled, run `sudo corepack enable` (the sudo is necessary for system-wide installation, if you use container, nvm etc... you might not be forced to use it)
|
||||
4. Install the dependencies: `yarn`
|
||||
|
||||
#### Run the electron app
|
||||
|
||||
`yarn compile:electron` (this is only needed the first time you run the app)
|
||||
|
||||
`yarn dev`
|
||||
|
||||
- If you want to build and launch the production app you can run `yarn build`. This will give you an executable inside the `/dist` folder. We use [electron-builder](https://github.com/electron-userland/electron-builder) to create distributable packages.
|
||||
|
||||
#### Run the web app for development
|
||||
|
||||
`yarn compile:web` (this is only needed the first time you run the app)
|
||||
|
||||
`yarn dev:web`
|
||||
|
||||
- This uses webpack-dev-server and includes hot-reloading. If you want to debug the [web server we use in production](https://github.com/lbryio/lbry-desktop/blob/master/src/platforms/web/server.js) you can run `yarn dev:web-server`. This starts a server at `localhost:1337` and does not include hot reloading.
|
||||
|
||||
#### Customize the web app
|
||||
|
||||
- In root directory, duplicate the .env.default file and rename it to .env then copy the code below and paste it anywhere in the .env file.
|
||||
|
||||
```
|
||||
cp .env.defaults .env
|
||||
nano .env
|
||||
```
|
||||
- To specify your own OG-IMAGE
|
||||
You can either place a png named v2-og.png in the /custom folder or specify the OG_IMAGE_URL in .env
|
||||
|
||||
- To specify your own channels to be followed on first run
|
||||
`AUTO_FOLLOW_URLS=lbry://@chan#123...a lbry://@chan2#456...a`
|
||||
|
||||
- If you want to customize the homepage content
|
||||
|
||||
1. add `CUSTOM_HOMEPAGE=true` to the '.env' file
|
||||
2. copy `/custom/homepage.example.js` to `/custom/homepage.js` and make desired changes to `homepage.js`
|
||||
|
||||
- If you want up to two custom sidebar links
|
||||
|
||||
```
|
||||
PINNED_URI_1=@someurl#2/someclaim#4
|
||||
PINNED_LABEL_1=Linktext
|
||||
|
||||
PINNED_URI_2=$/discover?t=tag&[queryparams]
|
||||
PINNED_LABEL_2=OtherLinkText
|
||||
```
|
||||
|
||||
- Finally `NODE_ENV=production yarn compile:web` to rebuild
|
||||
_Note: You don't need to edit the .env file in the /web folder - that is copied during compile._
|
||||
|
||||
#### Deploy the web app (_experimental_)
|
||||
|
||||
1. Create a server with a domain name and a reverse proxy https to port 1337.
|
||||
2. Install pm2, node v10, yarn
|
||||
3. Clone this repo
|
||||
4. Make any customizations as above
|
||||
5. Run `yarn` to install
|
||||
6. Run `NODE_ENV=production yarn compile:web` to build
|
||||
7. Set up pm2 to start ./web/index.js
|
||||
|
||||
#### Run both at the same time
|
||||
|
||||
Run the two commands above in separate terminal windows
|
||||
|
||||
```
|
||||
yarn dev
|
||||
|
||||
// in another terminal window
|
||||
yarn dev:web
|
||||
```
|
||||
|
||||
#### Resetting your Packages
|
||||
|
||||
If the app isn't building, or `yarn xxx` commands aren't working you may need to just reset your `node_modules`. To do so you can run: `rm -r node_modules && yarn` or `del /s /q node_modules && yarn` on Windows.
|
||||
|
@ -173,8 +110,9 @@ This project is MIT licensed. For the full license, see [LICENSE](LICENSE).
|
|||
|
||||
## Security
|
||||
|
||||
We take security seriously. Please contact security@lbry.com regarding any security issues. Our PGP key is [here](https://keybase.io/lbry/key.asc) if you need it. All releases are signed by [Sean Yesmunt](https://keybase.io/seanyesmunt/key.asc).
|
||||
We take security seriously. Please contact security@lbry.com regarding any security issues. Our PGP key is [here](https://lbry.com/faq/pgp-key) if you need it. Previous versions up to v0.50.2 were signed by [Sean Yesmunt](https://keybase.io/seanyesmunt/key.asc).
|
||||
New Releases are signed by [Jessop Breth](https://keybase.io/jessopb/key.asc).
|
||||
|
||||
## Contact
|
||||
|
||||
The primary contact for this project is [@seanyesmunt](https://github.com/seanyesmunt).
|
||||
The primary contact for this project is [@jessopb](https://github.com/jessopb).
|
||||
|
|
|
@ -7,6 +7,8 @@ module.exports = api => {
|
|||
'import-glob',
|
||||
'@babel/plugin-transform-runtime',
|
||||
['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }],
|
||||
['@babel/plugin-proposal-private-methods', { 'loose': false }],
|
||||
['@babel/plugin-proposal-private-property-in-object', { 'loose': false }],
|
||||
'@babel/plugin-transform-flow-strip-types',
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
'react-hot-loader/babel',
|
||||
|
|
BIN
build/cert-2021-2022.pfx
Normal file
BIN
build/cert-2021-2022.pfx
Normal file
Binary file not shown.
BIN
build/cert2023.pfx
Normal file
BIN
build/cert2023.pfx
Normal file
Binary file not shown.
14
build/entitlements.mac.plist
Normal file
14
build/entitlements.mac.plist
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
36
config.js
36
config.js
|
@ -8,11 +8,16 @@ const config = {
|
|||
WEBPACK_WEB_PORT: process.env.WEBPACK_WEB_PORT,
|
||||
WEBPACK_ELECTRON_PORT: process.env.WEBPACK_ELECTRON_PORT,
|
||||
WEB_SERVER_PORT: process.env.WEB_SERVER_PORT,
|
||||
LBRY_WEB_API: process.env.LBRY_WEB_API, //api.lbry.tv',
|
||||
LBRY_WEB_API: process.env.LBRY_WEB_API, //api.na-backend.odysee.com',
|
||||
LBRY_WEB_PUBLISH_API: process.env.LBRY_WEB_PUBLISH_API,
|
||||
LBRY_API_URL: process.env.LBRY_API_URL, //api.lbry.com',
|
||||
LBRY_WEB_STREAMING_API: process.env.LBRY_WEB_STREAMING_API, //cdn.lbryplayer.xyz',
|
||||
LBRY_WEB_STREAMING_API: process.env.LBRY_WEB_STREAMING_API, //player.odysee.com
|
||||
LBRY_WEB_BUFFER_API: process.env.LBRY_WEB_BUFFER_API,
|
||||
SEARCH_SERVER_API: process.env.SEARCH_SERVER_API,
|
||||
CLOUD_CONNECT_SITE_NAME: process.env.CLOUD_CONNECT_SITE_NAME,
|
||||
COMMENT_SERVER_API: process.env.COMMENT_SERVER_API,
|
||||
COMMENT_SERVER_NAME: process.env.COMMENT_SERVER_NAME,
|
||||
SOCKETY_SERVER_API: process.env.SOCKETY_SERVER_API,
|
||||
WELCOME_VERSION: process.env.WELCOME_VERSION,
|
||||
DOMAIN: process.env.DOMAIN,
|
||||
SHARE_DOMAIN_URL: process.env.SHARE_DOMAIN_URL,
|
||||
|
@ -22,21 +27,39 @@ const config = {
|
|||
SITE_NAME: process.env.SITE_NAME,
|
||||
SITE_DESCRIPTION: process.env.SITE_DESCRIPTION,
|
||||
SITE_HELP_EMAIL: process.env.SITE_HELP_EMAIL,
|
||||
// SOCIAL MEDIA
|
||||
TWITTER_ACCOUNT: process.env.TWITTER_ACCOUNT,
|
||||
// LOGO
|
||||
LOGO_TITLE: process.env.LOGO_TITLE,
|
||||
FAVICON: process.env.FAVICON,
|
||||
LOGO: process.env.LOGO,
|
||||
LOGO_TEXT_LIGHT: process.env.LOGO_TEXT_LIGHT,
|
||||
LOGO_TEXT_DARK: process.env.LOGO_TEXT_DARK,
|
||||
AVATAR_DEFAULT: process.env.AVATAR_DEFAULT,
|
||||
MISSING_THUMB_DEFAULT: process.env.MISSING_THUMB_DEFAULT,
|
||||
// OG
|
||||
OG_TITLE_SUFFIX: process.env.OG_TITLE_SUFFIX,
|
||||
OG_HOMEPAGE_TITLE: process.env.OG_HOMEPAGE_TITLE,
|
||||
OG_IMAGE_URL: process.env.OG_IMAGE_URL,
|
||||
// MASCOT
|
||||
YRBL_HAPPY_IMG_URL: process.env.YRBL_HAPPY_IMG_URL,
|
||||
YRBL_SAD_IMG_URL: process.env.YRBL_SAD_IMG_URL,
|
||||
LOGIN_IMG_URL: process.env.LOGIN_IMG_URL,
|
||||
SITE_CANONICAL_URL: process.env.SITE_CANONICAL_URL,
|
||||
DEFAULT_LANGUAGE: process.env.DEFAULT_LANGUAGE,
|
||||
AUTO_FOLLOW_CHANNELS: process.env.AUTO_FOLLOW_CHANNELS,
|
||||
UNSYNCED_SETTINGS: process.env.UNSYNCED_SETTINGS,
|
||||
|
||||
// ENABLE FEATURES
|
||||
ENABLE_COMMENT_REACTIONS: process.env.ENABLE_COMMENT_REACTIONS === 'true',
|
||||
ENABLE_FILE_REACTIONS: process.env.ENABLE_FILE_REACTIONS === 'true',
|
||||
ENABLE_CREATOR_REACTIONS: process.env.ENABLE_CREATOR_REACTIONS === 'true',
|
||||
ENABLE_NO_SOURCE_CLAIMS: process.env.ENABLE_NO_SOURCE_CLAIMS === 'true',
|
||||
ENABLE_PREROLL_ADS: process.env.ENABLE_PREROLL_ADS === 'true',
|
||||
CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS: process.env.CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS,
|
||||
CHANNEL_STAKED_LEVEL_LIVESTREAM: process.env.CHANNEL_STAKED_LEVEL_LIVESTREAM,
|
||||
WEB_PUBLISH_SIZE_LIMIT_GB: process.env.WEB_PUBLISH_SIZE_LIMIT_GB,
|
||||
LOADING_BAR_COLOR: process.env.LOADING_BAR_COLOR,
|
||||
SIMPLE_SITE: process.env.SIMPLE_SITE === 'true',
|
||||
SHOW_ADS: process.env.SHOW_ADS === 'true',
|
||||
PINNED_URI_1: process.env.PINNED_URI_1,
|
||||
|
@ -44,9 +67,16 @@ const config = {
|
|||
PINNED_URI_2: process.env.PINNED_URI_2,
|
||||
PINNED_LABEL_2: process.env.PINNED_LABEL_2,
|
||||
KNOWN_APP_DOMAINS: process.env.KNOWN_APP_DOMAINS ? process.env.KNOWN_APP_DOMAINS.split(',') : [],
|
||||
STRIPE_PUBLIC_KEY: process.env.STRIPE_PUBLIC_KEY,
|
||||
ENABLE_UI_NOTIFICATIONS: process.env.ENABLE_UI_NOTIFICATIONS === 'true',
|
||||
ENABLE_MATURE: process.env.ENABLE_MATURE === 'true',
|
||||
CUSTOM_HOMEPAGE: process.env.CUSTOM_HOMEPAGE === 'true',
|
||||
SHOW_TAGS_INTRO: process.env.SHOW_TAGS_INTRO === 'true',
|
||||
LIGHTHOUSE_DEFAULT_TYPES: process.env.LIGHTHOUSE_DEFAULT_TYPES,
|
||||
BRANDED_SITE: process.env.BRANDED_SITE,
|
||||
};
|
||||
|
||||
config.URL_LOCAL = `http://localhost:${config.WEB_SERVER_PORT}`;
|
||||
config.URL_DEV = `http://localhost:${config.WEBPACK_WEB_PORT}`;
|
||||
config.URL_LOCAL = `http://localhost:${config.WEB_SERVER_PORT}`;
|
||||
|
||||
module.exports = config;
|
||||
|
|
|
@ -20,11 +20,6 @@
|
|||
"to": "static/daemon/",
|
||||
"filter": ["**/*"]
|
||||
},
|
||||
{
|
||||
"from": "./static/lbry-first/",
|
||||
"to": "static/lbry-first/",
|
||||
"filter": ["**/*"]
|
||||
},
|
||||
{
|
||||
"from": "./static/img",
|
||||
"to": "static/img",
|
||||
|
@ -34,6 +29,10 @@
|
|||
"from": "./static/font",
|
||||
"to": "static/font",
|
||||
"filter": ["**/*"]
|
||||
},
|
||||
{
|
||||
"from": "./static/app-update.yml",
|
||||
"to": "app-update.yml"
|
||||
}
|
||||
],
|
||||
"publish": [
|
||||
|
@ -42,7 +41,11 @@
|
|||
}
|
||||
],
|
||||
"mac": {
|
||||
"category": "public.app-category.entertainment"
|
||||
"category": "public.app-category.entertainment",
|
||||
"entitlements": "build/entitlements.mac.plist",
|
||||
"entitlementsInherit": "build/entitlements.mac.plist",
|
||||
"hardenedRuntime" : true,
|
||||
"gatekeeperAssess": false
|
||||
},
|
||||
"dmg": {
|
||||
"iconSize": 128,
|
||||
|
@ -82,7 +85,7 @@
|
|||
}
|
||||
},
|
||||
"deb": {
|
||||
"depends": ["gconf2", "gconf-service", "libnotify4", "libappindicator1", "libxtst6", "libnss3"]
|
||||
"depends": ["gconf2", "gconf-service", "libnotify4", "libxtst6", "libnss3"]
|
||||
},
|
||||
"nsis": {
|
||||
"perMachine": true,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { spawn, execSync } from 'child_process';
|
||||
import { Lbry } from 'lbry-redux';
|
||||
import Lbry from 'lbry';
|
||||
|
||||
export default class Daemon {
|
||||
static lbrynetPath =
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { WEBPACK_ELECTRON_PORT } from 'config';
|
||||
import { app, BrowserWindow, dialog, shell, screen, nativeImage } from 'electron';
|
||||
import { app, BrowserWindow, dialog, screen, nativeImage } from 'electron';
|
||||
import isDev from 'electron-is-dev';
|
||||
import windowStateKeeper from 'electron-window-state';
|
||||
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
||||
|
@ -9,7 +9,8 @@ import { TO_TRAY_WHEN_CLOSED } from 'constants/settings';
|
|||
|
||||
import setupBarMenu from './menu/setupBarMenu';
|
||||
import * as PAGES from 'constants/pages';
|
||||
|
||||
const remote = require('@electron/remote/main');
|
||||
const shell = require('electron').shell;
|
||||
function GetAppLangCode() {
|
||||
// https://www.electronjs.org/docs/api/locales
|
||||
// 1. Gets the user locale.
|
||||
|
@ -54,6 +55,8 @@ export default appState => {
|
|||
webSecurity: !isDev,
|
||||
plugins: true,
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
enableRemoteModule: true, // see about removing this
|
||||
},
|
||||
};
|
||||
const lbryProto = 'lbry://';
|
||||
|
@ -61,6 +64,7 @@ export default appState => {
|
|||
const rendererURL = isDev ? `http://localhost:${WEBPACK_ELECTRON_PORT}` : `file://${__dirname}/index.html`;
|
||||
|
||||
let window = new BrowserWindow(windowConfiguration);
|
||||
remote.enable(window.webContents);
|
||||
|
||||
// Let us register listeners on the window, so we can update the state
|
||||
// automatically (the listeners will be removed when the window is closed)
|
||||
|
@ -91,7 +95,7 @@ export default appState => {
|
|||
|
||||
// is it a lbry://? pointing to an app page
|
||||
if (deepLinkingURI.includes(lbryProtoQ)) {
|
||||
let path = deepLinkingURI.substr(lbryProtoQ.length);
|
||||
let path = deepLinkingURI.slice(lbryProtoQ.length);
|
||||
let page = path.indexOf('?') >= 0 ? path.substring(0, path.indexOf('?')) : path;
|
||||
if (Object.values(PAGES).includes(page)) {
|
||||
deepLinkingURI = deepLinkingURI.replace(lbryProtoQ, '#/$/');
|
||||
|
@ -186,9 +190,13 @@ export default appState => {
|
|||
window = null;
|
||||
});
|
||||
|
||||
window.webContents.on('new-window', (event, url) => {
|
||||
event.preventDefault();
|
||||
shell.openExternal(url);
|
||||
window.webContents.setWindowOpenHandler((details) => {
|
||||
// Only open http and https links to prevent
|
||||
// security issues.
|
||||
if (['https:', 'http:'].includes(new URL(details.url).protocol)) {
|
||||
shell.openExternal(details.url);
|
||||
}
|
||||
return { action: 'deny' };
|
||||
});
|
||||
|
||||
window.webContents.on('update-target-url', (event, url) => {
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
import '@babel/polyfill';
|
||||
import SemVer from 'semver';
|
||||
import https from 'https';
|
||||
import { app, dialog, ipcMain, session, shell } from 'electron';
|
||||
import { app, dialog, ipcMain, session, shell, BrowserWindow } from 'electron';
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
import { Lbry } from 'lbry-redux';
|
||||
import Lbry from 'lbry';
|
||||
import LbryFirstInstance from './LbryFirstInstance';
|
||||
import Daemon from './Daemon';
|
||||
import isDev from 'electron-is-dev';
|
||||
|
@ -17,6 +17,17 @@ import startSandbox from './startSandbox';
|
|||
import installDevtools from './installDevtools';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { diskSpaceLinux, diskSpaceWindows, diskSpaceMac } from '../ui/util/diskspace';
|
||||
|
||||
const { download } = require('electron-dl');
|
||||
const mime = require('mime');
|
||||
const remote = require('@electron/remote/main');
|
||||
const os = require('os');
|
||||
const sudo = require('sudo-prompt');
|
||||
const probe = require('ffmpeg-probe');
|
||||
const MAX_IPC_SEND_BUFFER_SIZE = 500000000; // large files crash when serialized for ipc message
|
||||
|
||||
remote.initialize();
|
||||
const filePath = path.join(process.resourcesPath, 'static', 'upgradeDisabled');
|
||||
let upgradeDisabled;
|
||||
try {
|
||||
|
@ -26,11 +37,18 @@ try {
|
|||
upgradeDisabled = false;
|
||||
}
|
||||
autoUpdater.autoDownload = !upgradeDisabled;
|
||||
autoUpdater.allowPrerelease = false;
|
||||
|
||||
// This is set to true if an auto update has been downloaded through the Electron
|
||||
// auto-update system and is ready to install. If the user declined an update earlier,
|
||||
// it will still install on shutdown.
|
||||
let autoUpdateDownloaded = false;
|
||||
const UPDATE_STATE_INIT = 0;
|
||||
const UPDATE_STATE_CHECKING = 1;
|
||||
const UPDATE_STATE_UPDATES_FOUND = 2;
|
||||
const UPDATE_STATE_NO_UPDATES_FOUND = 3;
|
||||
const UPDATE_STATE_DOWNLOADING = 4;
|
||||
const UPDATE_STATE_DOWNLOADED = 5;
|
||||
let updateState = UPDATE_STATE_INIT;
|
||||
let updateDownloadItem;
|
||||
|
||||
const isAutoUpdateSupported = ['win32', 'darwin'].includes(process.platform) || !!process.env.APPIMAGE;
|
||||
|
||||
// This is used to keep track of whether we are showing the special dialog
|
||||
// that we show on Windows after you decline an upgrade and close the app later.
|
||||
|
@ -45,9 +63,15 @@ let daemon;
|
|||
let lbryFirst;
|
||||
|
||||
const appState = {};
|
||||
const PROTOCOL = 'lbry';
|
||||
|
||||
if (process.platform !== 'linux') {
|
||||
app.setAsDefaultProtocolClient('lbry');
|
||||
if (isDev && process.platform === 'win32') {
|
||||
// Setting this is required to get this working in dev mode.
|
||||
app.setAsDefaultProtocolClient(PROTOCOL, process.execPath, [
|
||||
path.resolve(process.argv[1]),
|
||||
]);
|
||||
} else if (process.platform !== 'linux') {
|
||||
app.setAsDefaultProtocolClient(PROTOCOL);
|
||||
}
|
||||
|
||||
app.name = 'LBRY';
|
||||
|
@ -149,9 +173,15 @@ if (!gotSingleInstanceLock) {
|
|||
app.on('second-instance', (event, argv) => {
|
||||
// Send the url to the app to navigate first, then focus
|
||||
if (rendererWindow) {
|
||||
if ((process.platform === 'win32' || process.platform === 'linux') && String(argv[1]).startsWith('lbry')) {
|
||||
let URI = argv[1];
|
||||
|
||||
// External uri (last item on argv):
|
||||
const EXTERNAL_URI = (argv.length) ? argv[argv.length - 1] : '';
|
||||
// Handle protocol requests for windows and linux
|
||||
const platforms = (process.platform === 'win32' || process.platform === 'linux');
|
||||
// Is LBRY protocol
|
||||
const isProtocolURI = String(EXTERNAL_URI).startsWith(PROTOCOL + '://');
|
||||
// External protocol requested:
|
||||
if (platforms && isProtocolURI) {
|
||||
let URI = EXTERNAL_URI;
|
||||
// Keep only command line / deep linked arguments
|
||||
// Windows normalizes URIs when they're passed in from other apps. On Windows, this tries to
|
||||
// restore the original URI that was typed.
|
||||
|
@ -211,7 +241,8 @@ app.on('activate', () => {
|
|||
app.on('will-quit', event => {
|
||||
if (
|
||||
process.platform === 'win32' &&
|
||||
autoUpdateDownloaded &&
|
||||
updateState === UPDATE_STATE_DOWNLOADED &&
|
||||
isAutoUpdateSupported &&
|
||||
!appState.autoUpdateAccepted &&
|
||||
!showingAutoUpdateCloseAlert
|
||||
) {
|
||||
|
@ -271,27 +302,118 @@ app.on('before-quit', () => {
|
|||
appState.isQuitting = true;
|
||||
});
|
||||
|
||||
ipcMain.on('upgrade', (event, installerPath) => {
|
||||
app.on('quit', () => {
|
||||
console.log('Launching upgrade installer at', installerPath);
|
||||
// This gets triggered called after *all* other quit-related events, so
|
||||
// we'll only get here if we're fully prepared and quitting for real.
|
||||
shell.openPath(installerPath);
|
||||
// Get the content of a file as a raw buffer of bytes.
|
||||
// Useful to convert a file path to a File instance.
|
||||
// Example:
|
||||
// const result = await ipcMain.invoke('get-file-from-path', 'path/to/file');
|
||||
// const file = new File([result.buffer], result.name);
|
||||
// NOTE: if path points to a folder, an empty
|
||||
// file will be given.
|
||||
ipcMain.handle('get-file-from-path', (event, path, readContents = true) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.stat(path, (error, stats) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
// Separate folders considering "\" and "/"
|
||||
// as separators (cross platform)
|
||||
const folders = path.split(/[\\/]/);
|
||||
const name = folders[folders.length - 1];
|
||||
if (stats.isDirectory()) {
|
||||
resolve({
|
||||
name,
|
||||
mime: undefined,
|
||||
path,
|
||||
buffer: new ArrayBuffer(0),
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!readContents) {
|
||||
resolve({
|
||||
name,
|
||||
mime: mime.getType(name) || undefined,
|
||||
path,
|
||||
buffer: new ArrayBuffer(0),
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Encoding null ensures data results in a Buffer.
|
||||
fs.readFile(path, { encoding: null }, (err, data) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve({
|
||||
name,
|
||||
mime: mime.getType(name) || undefined,
|
||||
path,
|
||||
buffer: data,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
// what to do if no shutdown in a long time?
|
||||
console.log('Update downloaded to', installerPath);
|
||||
console.log('The app will close and you will be prompted to install the latest version of LBRY.');
|
||||
console.log('After the install is complete, please reopen the app.');
|
||||
app.quit();
|
||||
});
|
||||
|
||||
autoUpdater.on('update-downloaded', () => {
|
||||
autoUpdateDownloaded = true;
|
||||
ipcMain.handle('get-file-details-from-path', async (event, path) => {
|
||||
const isFfMp4 = (ffprobeResults) => {
|
||||
return ffprobeResults &&
|
||||
ffprobeResults.format &&
|
||||
ffprobeResults.format.format_name &&
|
||||
ffprobeResults.format.format_name.includes('mp4');
|
||||
};
|
||||
const folders = path.split(/[\\/]/);
|
||||
const name = folders[folders.length - 1];
|
||||
let duration = 0, size = 0, mimeType;
|
||||
try {
|
||||
await fs.promises.stat(path);
|
||||
let ffprobeResults;
|
||||
try {
|
||||
ffprobeResults = await probe(path);
|
||||
duration = ffprobeResults.format.duration;
|
||||
size = ffprobeResults.format.size;
|
||||
} catch (e) {
|
||||
}
|
||||
let fileReadResult;
|
||||
if (size < MAX_IPC_SEND_BUFFER_SIZE) {
|
||||
try {
|
||||
fileReadResult = await fs.promises.readFile(path);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
}
|
||||
// TODO: use mmmagic to inspect file and get mime type
|
||||
mimeType = isFfMp4(ffprobeResults) ? 'video/mp4' : mime.getType(name);
|
||||
const fileData = {name, mime: mimeType || undefined, path, duration: duration, size, buffer: fileReadResult };
|
||||
return fileData;
|
||||
} catch (e) {
|
||||
// no stat
|
||||
return { error: 'no file' };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('autoUpdateAccepted', () => {
|
||||
appState.autoUpdateAccepted = true;
|
||||
autoUpdater.quitAndInstall();
|
||||
ipcMain.on('get-disk-space', async (event) => {
|
||||
try {
|
||||
const { data_dir } = await Lbry.settings_get();
|
||||
let diskSpace;
|
||||
switch (os.platform()) {
|
||||
case 'linux':
|
||||
diskSpace = await diskSpaceLinux(data_dir);
|
||||
break;
|
||||
case 'darwin':
|
||||
diskSpace = await diskSpaceMac(data_dir);
|
||||
break;
|
||||
case 'win32':
|
||||
diskSpace = await diskSpaceWindows(data_dir);
|
||||
break;
|
||||
default:
|
||||
throw new Error('unknown platform');
|
||||
}
|
||||
rendererWindow.webContents.send('send-disk-space', { diskSpace });
|
||||
} catch (e) {
|
||||
rendererWindow.webContents.send('send-disk-space', { error: e.message || e });
|
||||
console.log('Failed to get disk space', e);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('version-info-requested', () => {
|
||||
|
@ -386,3 +508,162 @@ process.on('uncaughtException', error => {
|
|||
if (daemon) daemon.quit();
|
||||
app.exit(1);
|
||||
});
|
||||
|
||||
// Auto updater
|
||||
autoUpdater.on('download-progress', () => {
|
||||
updateState = UPDATE_STATE_DOWNLOADING;
|
||||
});
|
||||
|
||||
autoUpdater.on('update-downloaded', () => {
|
||||
updateState = UPDATE_STATE_DOWNLOADED;
|
||||
|
||||
// If this download was trigger by
|
||||
// autoUpdateAccepted it means, the user
|
||||
// wants to install the new update but
|
||||
// needed to downloaded the files first.
|
||||
if (appState.autoUpdateAccepted) {
|
||||
autoUpdater.quitAndInstall();
|
||||
}
|
||||
});
|
||||
|
||||
autoUpdater.on('update-available', () => {
|
||||
if (updateState === UPDATE_STATE_DOWNLOADING) {
|
||||
return;
|
||||
}
|
||||
updateState = UPDATE_STATE_UPDATES_FOUND;
|
||||
});
|
||||
|
||||
autoUpdater.on('update-not-available', () => {
|
||||
updateState = UPDATE_STATE_NO_UPDATES_FOUND;
|
||||
});
|
||||
|
||||
autoUpdater.on('error', () => {
|
||||
if (updateState === UPDATE_STATE_DOWNLOADING) {
|
||||
updateState = UPDATE_STATE_UPDATES_FOUND;
|
||||
return;
|
||||
}
|
||||
updateState = UPDATE_STATE_INIT;
|
||||
});
|
||||
|
||||
// Manual (.deb) update
|
||||
ipcMain.on('cancel-download-upgrade', () => {
|
||||
if (updateDownloadItem) {
|
||||
// Cancel the download and execute the onCancel
|
||||
// callback set in the options.
|
||||
updateDownloadItem.cancel();
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('download-upgrade', (event, params) => {
|
||||
if (updateState !== UPDATE_STATE_UPDATES_FOUND) {
|
||||
return;
|
||||
}
|
||||
if (isAutoUpdateSupported) {
|
||||
updateState = UPDATE_STATE_DOWNLOADING;
|
||||
autoUpdater.downloadUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
const { url, options } = params;
|
||||
const dir = fs.mkdtempSync(app.getPath('temp') + path.sep);
|
||||
|
||||
updateState = UPDATE_STATE_DOWNLOADING;
|
||||
|
||||
// Grab the download item's handler to allow
|
||||
// cancelling the operation if required.
|
||||
options.onStarted = function(downloadItem) {
|
||||
updateDownloadItem = downloadItem;
|
||||
};
|
||||
options.onCancel = function() {
|
||||
updateState = UPDATE_STATE_UPDATES_FOUND;
|
||||
updateDownloadItem = undefined;
|
||||
};
|
||||
options.onProgress = function(p) {
|
||||
rendererWindow.webContents.send('download-progress-update', p);
|
||||
};
|
||||
options.onCompleted = function(c) {
|
||||
updateState = UPDATE_STATE_DOWNLOADED;
|
||||
updateDownloadItem = undefined;
|
||||
rendererWindow.webContents.send('download-update-complete', c);
|
||||
};
|
||||
options.directory = dir;
|
||||
const win = BrowserWindow.getFocusedWindow();
|
||||
download(win, url, options).catch(e => {
|
||||
updateState = UPDATE_STATE_UPDATES_FOUND;
|
||||
console.log('e', e);
|
||||
});
|
||||
});
|
||||
|
||||
// Update behavior
|
||||
ipcMain.on('autoUpdateAccepted', () => {
|
||||
appState.autoUpdateAccepted = true;
|
||||
|
||||
// quitAndInstall can only be called if the
|
||||
// update has been downloaded. Since the user
|
||||
// can disable auto updates, we have to make
|
||||
// sure it has been downloaded first.
|
||||
if (updateState === UPDATE_STATE_DOWNLOADED) {
|
||||
autoUpdater.quitAndInstall();
|
||||
return;
|
||||
}
|
||||
|
||||
if (updateState !== UPDATE_STATE_UPDATES_FOUND) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the update hasn't been downloaded,
|
||||
// start downloading it. After it's done, the
|
||||
// event 'update-downloaded' will be triggered,
|
||||
// where we will be able to resume the
|
||||
// update installation.
|
||||
updateState = UPDATE_STATE_DOWNLOADING;
|
||||
autoUpdater.downloadUpdate();
|
||||
});
|
||||
|
||||
ipcMain.on('check-for-updates', (event, autoDownload) => {
|
||||
if (![UPDATE_STATE_INIT, UPDATE_STATE_NO_UPDATES_FOUND].includes(updateState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateState = UPDATE_STATE_CHECKING;
|
||||
|
||||
// If autoDownload is true, checkForUpdates will begin the
|
||||
// download automatically.
|
||||
if (autoDownload) {
|
||||
updateState = UPDATE_STATE_DOWNLOADING;
|
||||
}
|
||||
|
||||
autoUpdater.autoDownload = autoDownload;
|
||||
autoUpdater.checkForUpdates();
|
||||
});
|
||||
|
||||
ipcMain.on('upgrade', (event, installerPath) => {
|
||||
// what to do if no shutdown in a long time?
|
||||
console.log('Update downloaded to', installerPath);
|
||||
console.log('The app will close and you will be prompted to install the latest version of LBRY.');
|
||||
console.log('After the install is complete, please reopen the app.');
|
||||
|
||||
// Prevent .deb package from opening with archive manager (Ubuntu >= 20)
|
||||
if (process.platform === 'linux' && !process.env.APPIMAGE) {
|
||||
sudo.exec(`dpkg -i ${installerPath}`, { name: app.name }, (err, stdout, stderr) => {
|
||||
if (err || stderr) {
|
||||
rendererWindow.webContents.send('upgrade-installing-error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Re-launch the application when the installation finishes.
|
||||
app.relaunch();
|
||||
app.quit();
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.on('quit', () => {
|
||||
console.log('Launching upgrade installer at', installerPath);
|
||||
// This gets triggered called after *all* other quit-related events, so
|
||||
// we'll only get here if we're fully prepared and quitting for real.
|
||||
shell.openPath(installerPath);
|
||||
});
|
||||
app.quit();
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import express from 'express';
|
||||
import unpackByOutpoint from './unpackByOutpoint';
|
||||
// import express from 'express';
|
||||
|
||||
// Polyfills and `lbry-redux`
|
||||
global.fetch = require('node-fetch');
|
||||
|
@ -8,31 +7,31 @@ if (typeof global.fetch === 'object') {
|
|||
global.fetch = global.fetch.default;
|
||||
}
|
||||
|
||||
const { Lbry } = require('lbry-redux');
|
||||
// const Lbry = require('lbry');
|
||||
|
||||
delete global.window;
|
||||
|
||||
export default async function startSandbox() {
|
||||
const port = 5278;
|
||||
const sandbox = express();
|
||||
// const port = 5278;
|
||||
// const sandbox = express();
|
||||
|
||||
sandbox.get('/set/:outpoint', async (req, res) => {
|
||||
const { outpoint } = req.params;
|
||||
|
||||
const resolvedPath = await unpackByOutpoint(Lbry, outpoint);
|
||||
|
||||
sandbox.use(`/sandbox/${outpoint}/`, express.static(resolvedPath));
|
||||
|
||||
res.send(`/sandbox/${outpoint}/`);
|
||||
});
|
||||
|
||||
sandbox
|
||||
.listen(port, 'localhost', () => console.log(`Sandbox listening on port ${port}.`))
|
||||
.on('error', err => {
|
||||
if (err.code === 'EADDRINUSE') {
|
||||
console.log(
|
||||
`Server already listening at localhost:${port}. This is probably another LBRY app running. If not, games in the app will not work.`
|
||||
);
|
||||
}
|
||||
});
|
||||
// sandbox.get('/set/:outpoint', async (req, res) => {
|
||||
// const { outpoint } = req.params;
|
||||
//
|
||||
// const resolvedPath = await unpackByOutpoint(Lbry, outpoint);
|
||||
//
|
||||
// sandbox.use(`/sandbox/${outpoint}/`, express.static(resolvedPath));
|
||||
//
|
||||
// res.send(`/sandbox/${outpoint}/`);
|
||||
// });
|
||||
//
|
||||
// sandbox
|
||||
// .listen(port, 'localhost', () => console.log(`Sandbox listening on port ${port}.`))
|
||||
// .on('error', err => {
|
||||
// if (err.code === 'EADDRINUSE') {
|
||||
// console.log(
|
||||
// `Server already listening at localhost:${port}. This is probably another LBRY app running. If not, games in the app will not work.`
|
||||
// );
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { unpackDirectory } from 'lbry-format';
|
||||
|
||||
async function unpackByOutpoint(lbry, outpoint) {
|
||||
const { items: claimFiles } = await lbry.file_list({ outpoint, full_status: true, page: 1, page_size: 1 });
|
||||
|
||||
if (claimFiles && claimFiles.length) {
|
||||
const claimFileInfo = claimFiles[0];
|
||||
const packFilePath = path.resolve(claimFileInfo.download_path);
|
||||
const unpackPath = path.normalize(path.join(claimFileInfo.download_directory, claimFileInfo.claim_name));
|
||||
|
||||
if (!fs.existsSync(unpackPath)) {
|
||||
await unpackDirectory(unpackPath, {
|
||||
fileName: packFilePath,
|
||||
});
|
||||
}
|
||||
|
||||
return unpackPath;
|
||||
}
|
||||
}
|
||||
|
||||
export default unpackByOutpoint;
|
184
extras/lbry-first/lbry-first.js
Normal file
184
extras/lbry-first/lbry-first.js
Normal file
|
@ -0,0 +1,184 @@
|
|||
// @flow
|
||||
/*
|
||||
LBRY FIRST does not work due to api changes
|
||||
*/
|
||||
import 'proxy-polyfill';
|
||||
|
||||
const CHECK_LBRYFIRST_STARTED_TRY_NUMBER = 200;
|
||||
//
|
||||
// Basic LBRYFIRST connection config
|
||||
// Offers a proxy to call LBRYFIRST methods
|
||||
|
||||
//
|
||||
const LbryFirst: LbryFirstTypes = {
|
||||
isConnected: false,
|
||||
connectPromise: null,
|
||||
lbryFirstConnectionString: 'http://localhost:1337/rpc',
|
||||
apiRequestHeaders: { 'Content-Type': 'application/json' },
|
||||
|
||||
// Allow overriding lbryFirst connection string (e.g. to `/api/proxy` for lbryweb)
|
||||
setLbryFirstConnectionString: (value: string) => {
|
||||
LbryFirst.lbryFirstConnectionString = value;
|
||||
},
|
||||
|
||||
setApiHeader: (key: string, value: string) => {
|
||||
LbryFirst.apiRequestHeaders = Object.assign(LbryFirst.apiRequestHeaders, { [key]: value });
|
||||
},
|
||||
|
||||
unsetApiHeader: key => {
|
||||
Object.keys(LbryFirst.apiRequestHeaders).includes(key) &&
|
||||
delete LbryFirst.apiRequestHeaders['key'];
|
||||
},
|
||||
// Allow overriding Lbry methods
|
||||
overrides: {},
|
||||
setOverride: (methodName, newMethod) => {
|
||||
LbryFirst.overrides[methodName] = newMethod;
|
||||
},
|
||||
getApiRequestHeaders: () => LbryFirst.apiRequestHeaders,
|
||||
|
||||
// LbryFirst Methods
|
||||
status: (params = {}) => lbryFirstCallWithResult('status', params),
|
||||
stop: () => lbryFirstCallWithResult('stop', {}),
|
||||
version: () => lbryFirstCallWithResult('version', {}),
|
||||
|
||||
// Upload to youtube
|
||||
upload: (params: { title: string, description: string, file_path: ?string } = {}) => {
|
||||
// Only upload when originally publishing for now
|
||||
if (!params.file_path) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const uploadParams: {
|
||||
Title: string,
|
||||
Description: string,
|
||||
FilePath: string,
|
||||
Category: string,
|
||||
Keywords: string,
|
||||
} = {
|
||||
Title: params.title,
|
||||
Description: params.description,
|
||||
FilePath: params.file_path,
|
||||
Category: '',
|
||||
Keywords: '',
|
||||
};
|
||||
|
||||
return lbryFirstCallWithResult('youtube.Upload', uploadParams);
|
||||
},
|
||||
|
||||
hasYTAuth: (token: string) => {
|
||||
const hasYTAuthParams = {};
|
||||
hasYTAuthParams.AuthToken = token;
|
||||
return lbryFirstCallWithResult('youtube.HasAuth', hasYTAuthParams);
|
||||
},
|
||||
|
||||
ytSignup: () => {
|
||||
const emptyParams = {};
|
||||
return lbryFirstCallWithResult('youtube.Signup', emptyParams);
|
||||
},
|
||||
|
||||
remove: () => {
|
||||
const emptyParams = {};
|
||||
return lbryFirstCallWithResult('youtube.Remove', emptyParams);
|
||||
},
|
||||
|
||||
// Connect to lbry-first
|
||||
connect: () => {
|
||||
if (LbryFirst.connectPromise === null) {
|
||||
LbryFirst.connectPromise = new Promise((resolve, reject) => {
|
||||
let tryNum = 0;
|
||||
// Check every half second to see if the lbryFirst is accepting connections
|
||||
function checkLbryFirstStarted() {
|
||||
tryNum += 1;
|
||||
LbryFirst.status()
|
||||
.then(resolve)
|
||||
.catch(() => {
|
||||
if (tryNum <= CHECK_LBRYFIRST_STARTED_TRY_NUMBER) {
|
||||
setTimeout(checkLbryFirstStarted, tryNum < 50 ? 400 : 1000);
|
||||
} else {
|
||||
reject(new Error('Unable to connect to LBRY'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
checkLbryFirstStarted();
|
||||
});
|
||||
}
|
||||
|
||||
// Flow thinks this could be empty, but it will always return a promise
|
||||
// $FlowFixMe
|
||||
return LbryFirst.connectPromise;
|
||||
},
|
||||
};
|
||||
|
||||
function checkAndParse(response) {
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
return response.json();
|
||||
}
|
||||
return response.json().then(json => {
|
||||
let error;
|
||||
if (json.error) {
|
||||
const errorMessage = typeof json.error === 'object' ? json.error.message : json.error;
|
||||
error = new Error(errorMessage);
|
||||
} else {
|
||||
error = new Error('Protocol error with unknown response signature');
|
||||
}
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
export function apiCall(method: string, params: ?{}, resolve: Function, reject: Function) {
|
||||
const counter = new Date().getTime();
|
||||
const paramsArray = [params];
|
||||
const options = {
|
||||
method: 'POST',
|
||||
headers: LbryFirst.apiRequestHeaders,
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
method,
|
||||
params: paramsArray,
|
||||
id: counter,
|
||||
}),
|
||||
};
|
||||
|
||||
return fetch(LbryFirst.lbryFirstConnectionString, options)
|
||||
.then(checkAndParse)
|
||||
.then(response => {
|
||||
const error = response.error || (response.result && response.result.error);
|
||||
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
return resolve(response.result);
|
||||
})
|
||||
.catch(reject);
|
||||
}
|
||||
|
||||
function lbryFirstCallWithResult(name: string, params: ?{} = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
apiCall(
|
||||
name,
|
||||
params,
|
||||
result => {
|
||||
resolve(result);
|
||||
},
|
||||
reject
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// This is only for a fallback
|
||||
// If there is a LbryFirst method that is being called by an app, it should be added to /flow-typed/LbryFirst.js
|
||||
const lbryFirstProxy = new Proxy(LbryFirst, {
|
||||
get(target: LbryFirstTypes, name: string) {
|
||||
if (name in target) {
|
||||
return target[name];
|
||||
}
|
||||
|
||||
return (params = {}) =>
|
||||
new Promise((resolve, reject) => {
|
||||
apiCall(name, params, resolve, reject);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default lbryFirstProxy;
|
97
extras/lbryinc/constants/action_types.js
Normal file
97
extras/lbryinc/constants/action_types.js
Normal file
|
@ -0,0 +1,97 @@
|
|||
// Claims
|
||||
export const FETCH_FEATURED_CONTENT_STARTED = 'FETCH_FEATURED_CONTENT_STARTED';
|
||||
export const FETCH_FEATURED_CONTENT_COMPLETED = 'FETCH_FEATURED_CONTENT_COMPLETED';
|
||||
export const FETCH_TRENDING_CONTENT_STARTED = 'FETCH_TRENDING_CONTENT_STARTED';
|
||||
export const FETCH_TRENDING_CONTENT_COMPLETED = 'FETCH_TRENDING_CONTENT_COMPLETED';
|
||||
export const RESOLVE_URIS_STARTED = 'RESOLVE_URIS_STARTED';
|
||||
export const RESOLVE_URIS_COMPLETED = 'RESOLVE_URIS_COMPLETED';
|
||||
export const FETCH_CHANNEL_CLAIMS_STARTED = 'FETCH_CHANNEL_CLAIMS_STARTED';
|
||||
export const FETCH_CHANNEL_CLAIMS_COMPLETED = 'FETCH_CHANNEL_CLAIMS_COMPLETED';
|
||||
export const FETCH_CHANNEL_CLAIM_COUNT_STARTED = 'FETCH_CHANNEL_CLAIM_COUNT_STARTED';
|
||||
export const FETCH_CHANNEL_CLAIM_COUNT_COMPLETED = 'FETCH_CHANNEL_CLAIM_COUNT_COMPLETED';
|
||||
export const FETCH_CLAIM_LIST_MINE_STARTED = 'FETCH_CLAIM_LIST_MINE_STARTED';
|
||||
export const FETCH_CLAIM_LIST_MINE_COMPLETED = 'FETCH_CLAIM_LIST_MINE_COMPLETED';
|
||||
export const ABANDON_CLAIM_STARTED = 'ABANDON_CLAIM_STARTED';
|
||||
export const ABANDON_CLAIM_SUCCEEDED = 'ABANDON_CLAIM_SUCCEEDED';
|
||||
export const FETCH_CHANNEL_LIST_STARTED = 'FETCH_CHANNEL_LIST_STARTED';
|
||||
export const FETCH_CHANNEL_LIST_COMPLETED = 'FETCH_CHANNEL_LIST_COMPLETED';
|
||||
export const CREATE_CHANNEL_STARTED = 'CREATE_CHANNEL_STARTED';
|
||||
export const CREATE_CHANNEL_COMPLETED = 'CREATE_CHANNEL_COMPLETED';
|
||||
export const PUBLISH_STARTED = 'PUBLISH_STARTED';
|
||||
export const PUBLISH_COMPLETED = 'PUBLISH_COMPLETED';
|
||||
export const PUBLISH_FAILED = 'PUBLISH_FAILED';
|
||||
export const SET_PLAYING_URI = 'SET_PLAYING_URI';
|
||||
export const SET_CONTENT_POSITION = 'SET_CONTENT_POSITION';
|
||||
export const SET_CONTENT_LAST_VIEWED = 'SET_CONTENT_LAST_VIEWED';
|
||||
export const CLEAR_CONTENT_HISTORY_URI = 'CLEAR_CONTENT_HISTORY_URI';
|
||||
export const CLEAR_CONTENT_HISTORY_ALL = 'CLEAR_CONTENT_HISTORY_ALL';
|
||||
|
||||
// Subscriptions
|
||||
export const CHANNEL_SUBSCRIBE = 'CHANNEL_SUBSCRIBE';
|
||||
export const CHANNEL_UNSUBSCRIBE = 'CHANNEL_UNSUBSCRIBE';
|
||||
export const CHANNEL_SUBSCRIPTION_ENABLE_NOTIFICATIONS =
|
||||
'CHANNEL_SUBSCRIPTION_ENABLE_NOTIFICATIONS';
|
||||
export const CHANNEL_SUBSCRIPTION_DISABLE_NOTIFICATIONS =
|
||||
'CHANNEL_SUBSCRIPTION_DISABLE_NOTIFICATIONS';
|
||||
export const HAS_FETCHED_SUBSCRIPTIONS = 'HAS_FETCHED_SUBSCRIPTIONS';
|
||||
export const SET_SUBSCRIPTION_LATEST = 'SET_SUBSCRIPTION_LATEST';
|
||||
export const UPDATE_SUBSCRIPTION_UNREADS = 'UPDATE_SUBSCRIPTION_UNREADS';
|
||||
export const REMOVE_SUBSCRIPTION_UNREADS = 'REMOVE_SUBSCRIPTION_UNREADS';
|
||||
export const CHECK_SUBSCRIPTION_STARTED = 'CHECK_SUBSCRIPTION_STARTED';
|
||||
export const CHECK_SUBSCRIPTION_COMPLETED = 'CHECK_SUBSCRIPTION_COMPLETED';
|
||||
export const CHECK_SUBSCRIPTIONS_SUBSCRIBE = 'CHECK_SUBSCRIPTIONS_SUBSCRIBE';
|
||||
export const FETCH_SUBSCRIPTIONS_START = 'FETCH_SUBSCRIPTIONS_START';
|
||||
export const FETCH_SUBSCRIPTIONS_FAIL = 'FETCH_SUBSCRIPTIONS_FAIL';
|
||||
export const FETCH_SUBSCRIPTIONS_SUCCESS = 'FETCH_SUBSCRIPTIONS_SUCCESS';
|
||||
export const SET_VIEW_MODE = 'SET_VIEW_MODE';
|
||||
export const GET_SUGGESTED_SUBSCRIPTIONS_START = 'GET_SUGGESTED_SUBSCRIPTIONS_START';
|
||||
export const GET_SUGGESTED_SUBSCRIPTIONS_SUCCESS = 'GET_SUGGESTED_SUBSCRIPTIONS_SUCCESS';
|
||||
export const GET_SUGGESTED_SUBSCRIPTIONS_FAIL = 'GET_SUGGESTED_SUBSCRIPTIONS_FAIL';
|
||||
export const SUBSCRIPTION_FIRST_RUN_COMPLETED = 'SUBSCRIPTION_FIRST_RUN_COMPLETED';
|
||||
export const VIEW_SUGGESTED_SUBSCRIPTIONS = 'VIEW_SUGGESTED_SUBSCRIPTIONS';
|
||||
|
||||
// Blacklist
|
||||
export const FETCH_BLACK_LISTED_CONTENT_STARTED = 'FETCH_BLACK_LISTED_CONTENT_STARTED';
|
||||
export const FETCH_BLACK_LISTED_CONTENT_COMPLETED = 'FETCH_BLACK_LISTED_CONTENT_COMPLETED';
|
||||
export const FETCH_BLACK_LISTED_CONTENT_FAILED = 'FETCH_BLACK_LISTED_CONTENT_FAILED';
|
||||
export const BLACK_LISTED_CONTENT_SUBSCRIBE = 'BLACK_LISTED_CONTENT_SUBSCRIBE';
|
||||
|
||||
// Filtered list
|
||||
export const FETCH_FILTERED_CONTENT_STARTED = 'FETCH_FILTERED_CONTENT_STARTED';
|
||||
export const FETCH_FILTERED_CONTENT_COMPLETED = 'FETCH_FILTERED_CONTENT_COMPLETED';
|
||||
export const FETCH_FILTERED_CONTENT_FAILED = 'FETCH_FILTERED_CONTENT_FAILED';
|
||||
export const FILTERED_CONTENT_SUBSCRIBE = 'FILTERED_CONTENT_SUBSCRIBE';
|
||||
|
||||
// Cost Info
|
||||
export const FETCH_COST_INFO_STARTED = 'FETCH_COST_INFO_STARTED';
|
||||
export const FETCH_COST_INFO_COMPLETED = 'FETCH_COST_INFO_COMPLETED';
|
||||
|
||||
// Stats
|
||||
export const FETCH_VIEW_COUNT_STARTED = 'FETCH_VIEW_COUNT_STARTED';
|
||||
export const FETCH_VIEW_COUNT_FAILED = 'FETCH_VIEW_COUNT_FAILED';
|
||||
export const FETCH_VIEW_COUNT_COMPLETED = 'FETCH_VIEW_COUNT_COMPLETED';
|
||||
export const FETCH_SUB_COUNT_STARTED = 'FETCH_SUB_COUNT_STARTED';
|
||||
export const FETCH_SUB_COUNT_FAILED = 'FETCH_SUB_COUNT_FAILED';
|
||||
export const FETCH_SUB_COUNT_COMPLETED = 'FETCH_SUB_COUNT_COMPLETED';
|
||||
|
||||
// Cross-device Sync
|
||||
export const GET_SYNC_STARTED = 'GET_SYNC_STARTED';
|
||||
export const GET_SYNC_COMPLETED = 'GET_SYNC_COMPLETED';
|
||||
export const GET_SYNC_FAILED = 'GET_SYNC_FAILED';
|
||||
export const SET_SYNC_STARTED = 'SET_SYNC_STARTED';
|
||||
export const SET_SYNC_FAILED = 'SET_SYNC_FAILED';
|
||||
export const SET_SYNC_COMPLETED = 'SET_SYNC_COMPLETED';
|
||||
export const SET_DEFAULT_ACCOUNT = 'SET_DEFAULT_ACCOUNT';
|
||||
export const SYNC_APPLY_STARTED = 'SYNC_APPLY_STARTED';
|
||||
export const SYNC_APPLY_COMPLETED = 'SYNC_APPLY_COMPLETED';
|
||||
export const SYNC_APPLY_FAILED = 'SYNC_APPLY_FAILED';
|
||||
export const SYNC_APPLY_BAD_PASSWORD = 'SYNC_APPLY_BAD_PASSWORD';
|
||||
export const SYNC_RESET = 'SYNC_RESET';
|
||||
|
||||
// Lbry.tv
|
||||
export const UPDATE_UPLOAD_PROGRESS = 'UPDATE_UPLOAD_PROGRESS';
|
||||
|
||||
// User
|
||||
export const GENERATE_AUTH_TOKEN_FAILURE = 'GENERATE_AUTH_TOKEN_FAILURE';
|
||||
export const GENERATE_AUTH_TOKEN_STARTED = 'GENERATE_AUTH_TOKEN_STARTED';
|
||||
export const GENERATE_AUTH_TOKEN_SUCCESS = 'GENERATE_AUTH_TOKEN_SUCCESS';
|
5
extras/lbryinc/constants/claim.js
Normal file
5
extras/lbryinc/constants/claim.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
export const MINIMUM_PUBLISH_BID = 0.00000001;
|
||||
|
||||
export const CHANNEL_ANONYMOUS = 'anonymous';
|
||||
export const CHANNEL_NEW = 'new';
|
||||
export const PAGE_SIZE = 20;
|
4
extras/lbryinc/constants/errors.js
Normal file
4
extras/lbryinc/constants/errors.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
export const ALREADY_CLAIMED =
|
||||
'once the invite reward has been claimed the referrer cannot be changed';
|
||||
export const REFERRER_NOT_FOUND =
|
||||
'A lbry.tv account could not be found for the referrer you provided.';
|
11
extras/lbryinc/constants/youtube.js
Normal file
11
extras/lbryinc/constants/youtube.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
export const YOUTUBE_SYNC_NOT_TRANSFERRED = 'not_transferred';
|
||||
export const YOUTUBE_SYNC_PENDING = 'pending';
|
||||
export const YOUTUBE_SYNC_PENDING_EMAIL = 'pendingemail';
|
||||
export const YOUTUBE_SYNC_PENDING_TRANSFER = 'pending_transfer';
|
||||
export const YOUTUBE_SYNC_COMPLETED_TRANSFER = 'completed_transfer';
|
||||
export const YOUTUBE_SYNC_QUEUED = 'queued';
|
||||
export const YOUTUBE_SYNC_SYNCING = 'syncing';
|
||||
export const YOUTUBE_SYNC_SYNCED = 'synced';
|
||||
export const YOUTUBE_SYNC_FAILED = 'failed';
|
||||
export const YOUTUBE_SYNC_PENDINGUPGRADE = 'pendingupgrade';
|
||||
export const YOUTUBE_SYNC_ABANDONDED = 'abandoned';
|
71
extras/lbryinc/index.js
Normal file
71
extras/lbryinc/index.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
import * as LBRYINC_ACTIONS from 'constants/action_types';
|
||||
import * as YOUTUBE_STATUSES from 'constants/youtube';
|
||||
import * as ERRORS from 'constants/errors';
|
||||
import Lbryio from './lbryio';
|
||||
|
||||
export { Lbryio };
|
||||
|
||||
// constants
|
||||
export { LBRYINC_ACTIONS, YOUTUBE_STATUSES, ERRORS };
|
||||
|
||||
// utils
|
||||
export { doTransifexUpload } from 'util/transifex-upload';
|
||||
|
||||
// actions
|
||||
export { doGenerateAuthToken } from './redux/actions/auth';
|
||||
export { doFetchCostInfoForUri } from './redux/actions/cost_info';
|
||||
export { doBlackListedOutpointsSubscribe } from './redux/actions/blacklist';
|
||||
export { doFilteredOutpointsSubscribe } from './redux/actions/filtered';
|
||||
export { doFetchViewCount, doFetchSubCount } from './redux/actions/stats';
|
||||
export {
|
||||
doCheckSync,
|
||||
doGetSync,
|
||||
doSetSync,
|
||||
doSetDefaultAccount,
|
||||
doSyncApply,
|
||||
doResetSync,
|
||||
doSyncEncryptAndDecrypt,
|
||||
} from 'redux/actions/sync';
|
||||
|
||||
// reducers
|
||||
export { authReducer } from './redux/reducers/auth';
|
||||
export { costInfoReducer } from './redux/reducers/cost_info';
|
||||
export { blacklistReducer } from './redux/reducers/blacklist';
|
||||
export { filteredReducer } from './redux/reducers/filtered';
|
||||
export { statsReducer } from './redux/reducers/stats';
|
||||
export { syncReducer } from './redux/reducers/sync';
|
||||
|
||||
// selectors
|
||||
export { selectAuthToken, selectIsAuthenticating } from './redux/selectors/auth';
|
||||
export {
|
||||
selectFetchingCostInfoForUri,
|
||||
selectCostInfoForUri,
|
||||
selectAllCostInfoByUri,
|
||||
selectFetchingCostInfo,
|
||||
} from './redux/selectors/cost_info';
|
||||
export {
|
||||
selectBlackListedOutpoints,
|
||||
selectBlacklistedOutpointMap,
|
||||
} from './redux/selectors/blacklist';
|
||||
export { selectFilteredOutpoints, selectFilteredOutpointMap } from './redux/selectors/filtered';
|
||||
export {
|
||||
selectViewCount,
|
||||
selectViewCountForUri,
|
||||
// makeSelectViewCountForUri, // deprecated
|
||||
selectSubCountForUri,
|
||||
// makeSelectSubCountForUri, // deprecated
|
||||
} from './redux/selectors/stats';
|
||||
export { selectBanStateForUri } from './redux/selectors/ban';
|
||||
export {
|
||||
selectHasSyncedWallet,
|
||||
selectSyncData,
|
||||
selectSyncHash,
|
||||
selectSetSyncErrorMessage,
|
||||
selectGetSyncErrorMessage,
|
||||
selectGetSyncIsPending,
|
||||
selectSetSyncIsPending,
|
||||
selectSyncApplyIsPending,
|
||||
selectHashChanged,
|
||||
selectSyncApplyErrorMessage,
|
||||
selectSyncApplyPasswordError,
|
||||
} from './redux/selectors/sync';
|
238
extras/lbryinc/lbryio.js
Normal file
238
extras/lbryinc/lbryio.js
Normal file
|
@ -0,0 +1,238 @@
|
|||
import * as ACTIONS from 'constants/action_types';
|
||||
import Lbry from 'lbry';
|
||||
import querystring from 'querystring';
|
||||
|
||||
const Lbryio = {
|
||||
enabled: true,
|
||||
authenticationPromise: null,
|
||||
exchangePromise: null,
|
||||
exchangeLastFetched: null,
|
||||
CONNECTION_STRING: 'https://api.lbry.com/',
|
||||
};
|
||||
|
||||
const EXCHANGE_RATE_TIMEOUT = 20 * 60 * 1000;
|
||||
const INTERNAL_APIS_DOWN = 'internal_apis_down';
|
||||
|
||||
// We can't use env's because they aren't passed into node_modules
|
||||
Lbryio.setLocalApi = endpoint => {
|
||||
Lbryio.CONNECTION_STRING = endpoint.replace(/\/*$/, '/'); // exactly one slash at the end;
|
||||
};
|
||||
|
||||
Lbryio.call = (resource, action, params = {}, method = 'get') => {
|
||||
if (!Lbryio.enabled) {
|
||||
return Promise.reject(new Error(__('LBRY internal API is disabled')));
|
||||
}
|
||||
|
||||
if (!(method === 'get' || method === 'post')) {
|
||||
return Promise.reject(new Error(__('Invalid method')));
|
||||
}
|
||||
|
||||
function checkAndParse(response) {
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
if (response.status === 500) {
|
||||
return Promise.reject(INTERNAL_APIS_DOWN);
|
||||
}
|
||||
|
||||
if (response)
|
||||
return response.json().then(json => {
|
||||
let error;
|
||||
if (json.error) {
|
||||
error = new Error(json.error);
|
||||
} else {
|
||||
error = new Error('Unknown API error signature');
|
||||
}
|
||||
error.response = response; // This is primarily a hack used in actions/user.js
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
function makeRequest(url, options) {
|
||||
return fetch(url, options).then(checkAndParse);
|
||||
}
|
||||
|
||||
return Lbryio.getAuthToken().then(token => {
|
||||
const fullParams = { auth_token: token, ...params };
|
||||
Object.keys(fullParams).forEach(key => {
|
||||
const value = fullParams[key];
|
||||
if (typeof value === 'object') {
|
||||
fullParams[key] = JSON.stringify(value);
|
||||
}
|
||||
});
|
||||
|
||||
const qs = querystring.stringify(fullParams);
|
||||
let url = `${Lbryio.CONNECTION_STRING}${resource}/${action}?${qs}`;
|
||||
|
||||
let options = {
|
||||
method: 'GET',
|
||||
};
|
||||
|
||||
if (method === 'post') {
|
||||
options = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: qs,
|
||||
};
|
||||
url = `${Lbryio.CONNECTION_STRING}${resource}/${action}`;
|
||||
}
|
||||
|
||||
return makeRequest(url, options).then(response => response.data);
|
||||
});
|
||||
};
|
||||
|
||||
Lbryio.authToken = null;
|
||||
|
||||
Lbryio.getAuthToken = () =>
|
||||
new Promise(resolve => {
|
||||
if (Lbryio.authToken) {
|
||||
resolve(Lbryio.authToken);
|
||||
} else if (Lbryio.overrides.getAuthToken) {
|
||||
Lbryio.overrides.getAuthToken().then(token => {
|
||||
resolve(token);
|
||||
});
|
||||
} else if (typeof window !== 'undefined') {
|
||||
const { store } = window;
|
||||
if (store) {
|
||||
const state = store.getState();
|
||||
const token = state.auth ? state.auth.authToken : null;
|
||||
Lbryio.authToken = token;
|
||||
resolve(token);
|
||||
}
|
||||
|
||||
resolve(null);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
|
||||
Lbryio.getCurrentUser = () => Lbryio.call('user', 'me');
|
||||
|
||||
Lbryio.authenticate = (domain, language) => {
|
||||
if (!Lbryio.enabled) {
|
||||
const params = {
|
||||
id: 1,
|
||||
primary_email: 'disabled@lbry.io',
|
||||
has_verified_email: true,
|
||||
is_identity_verified: true,
|
||||
is_reward_approved: false,
|
||||
language: language || 'en',
|
||||
};
|
||||
|
||||
return new Promise(resolve => {
|
||||
resolve(params);
|
||||
});
|
||||
}
|
||||
|
||||
if (Lbryio.authenticationPromise === null) {
|
||||
Lbryio.authenticationPromise = new Promise((resolve, reject) => {
|
||||
Lbryio.getAuthToken()
|
||||
.then(token => {
|
||||
if (!token || token.length > 60) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check that token works
|
||||
return Lbryio.getCurrentUser()
|
||||
.then(user => user)
|
||||
.catch(error => {
|
||||
if (error === INTERNAL_APIS_DOWN) {
|
||||
throw new Error('Internal APIS down');
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
})
|
||||
.then(user => {
|
||||
if (user) {
|
||||
return user;
|
||||
}
|
||||
|
||||
return Lbry.status()
|
||||
.then(
|
||||
status =>
|
||||
new Promise((res, rej) => {
|
||||
const appId =
|
||||
domain && domain !== 'lbry.tv'
|
||||
? (domain.replace(/[.]/gi, '') + status.installation_id).slice(0, 66)
|
||||
: status.installation_id;
|
||||
Lbryio.call(
|
||||
'user',
|
||||
'new',
|
||||
{
|
||||
auth_token: '',
|
||||
language: language || 'en',
|
||||
app_id: appId,
|
||||
},
|
||||
'post'
|
||||
)
|
||||
.then(response => {
|
||||
if (!response.auth_token) {
|
||||
throw new Error('auth_token was not set in the response');
|
||||
}
|
||||
|
||||
const { store } = window;
|
||||
if (Lbryio.overrides.setAuthToken) {
|
||||
Lbryio.overrides.setAuthToken(response.auth_token);
|
||||
}
|
||||
|
||||
if (store) {
|
||||
store.dispatch({
|
||||
type: ACTIONS.GENERATE_AUTH_TOKEN_SUCCESS,
|
||||
data: { authToken: response.auth_token },
|
||||
});
|
||||
}
|
||||
Lbryio.authToken = response.auth_token;
|
||||
return res(response);
|
||||
})
|
||||
.catch(error => rej(error));
|
||||
})
|
||||
)
|
||||
.then(newUser => {
|
||||
if (!newUser) {
|
||||
return Lbryio.getCurrentUser();
|
||||
}
|
||||
return newUser;
|
||||
});
|
||||
})
|
||||
.then(resolve, reject);
|
||||
});
|
||||
}
|
||||
|
||||
return Lbryio.authenticationPromise;
|
||||
};
|
||||
|
||||
Lbryio.getStripeToken = () =>
|
||||
Lbryio.CONNECTION_STRING.startsWith('http://localhost:')
|
||||
? 'pk_test_NoL1JWL7i1ipfhVId5KfDZgo'
|
||||
: 'pk_live_e8M4dRNnCCbmpZzduEUZBgJO';
|
||||
|
||||
Lbryio.getExchangeRates = () => {
|
||||
if (
|
||||
!Lbryio.exchangeLastFetched ||
|
||||
Date.now() - Lbryio.exchangeLastFetched > EXCHANGE_RATE_TIMEOUT
|
||||
) {
|
||||
Lbryio.exchangePromise = new Promise((resolve, reject) => {
|
||||
Lbryio.call('lbc', 'exchange_rate', {}, 'get', true)
|
||||
.then(({ lbc_usd: LBC_USD, lbc_btc: LBC_BTC, btc_usd: BTC_USD }) => {
|
||||
const rates = { LBC_USD, LBC_BTC, BTC_USD };
|
||||
resolve(rates);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
Lbryio.exchangeLastFetched = Date.now();
|
||||
}
|
||||
return Lbryio.exchangePromise;
|
||||
};
|
||||
|
||||
// Allow overriding lbryio methods
|
||||
// The desktop app will need to use it for getAuthToken because we use electron's ipcRenderer
|
||||
Lbryio.overrides = {};
|
||||
Lbryio.setOverride = (methodName, newMethod) => {
|
||||
Lbryio.overrides[methodName] = newMethod;
|
||||
};
|
||||
|
||||
export default Lbryio;
|
38
extras/lbryinc/redux/actions/auth.js
Normal file
38
extras/lbryinc/redux/actions/auth.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
import * as ACTIONS from 'constants/action_types';
|
||||
import { Lbryio } from 'lbryinc';
|
||||
|
||||
export function doGenerateAuthToken(installationId) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: ACTIONS.GENERATE_AUTH_TOKEN_STARTED,
|
||||
});
|
||||
|
||||
Lbryio.call(
|
||||
'user',
|
||||
'new',
|
||||
{
|
||||
auth_token: '',
|
||||
language: 'en',
|
||||
app_id: installationId,
|
||||
},
|
||||
'post'
|
||||
)
|
||||
.then(response => {
|
||||
if (!response.auth_token) {
|
||||
dispatch({
|
||||
type: ACTIONS.GENERATE_AUTH_TOKEN_FAILURE,
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: ACTIONS.GENERATE_AUTH_TOKEN_SUCCESS,
|
||||
data: { authToken: response.auth_token },
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch({
|
||||
type: ACTIONS.GENERATE_AUTH_TOKEN_FAILURE,
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
52
extras/lbryinc/redux/actions/blacklist.js
Normal file
52
extras/lbryinc/redux/actions/blacklist.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
import { Lbryio } from 'lbryinc';
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
|
||||
const CHECK_BLACK_LISTED_CONTENT_INTERVAL = 60 * 60 * 1000;
|
||||
|
||||
export function doFetchBlackListedOutpoints() {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_BLACK_LISTED_CONTENT_STARTED,
|
||||
});
|
||||
|
||||
const success = ({ outpoints }) => {
|
||||
const splitOutpoints = [];
|
||||
if (outpoints) {
|
||||
outpoints.forEach((outpoint, index) => {
|
||||
const [txid, nout] = outpoint.split(':');
|
||||
|
||||
splitOutpoints[index] = { txid, nout: Number.parseInt(nout, 10) };
|
||||
});
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_BLACK_LISTED_CONTENT_COMPLETED,
|
||||
data: {
|
||||
outpoints: splitOutpoints,
|
||||
success: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const failure = ({ message: error }) => {
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_BLACK_LISTED_CONTENT_FAILED,
|
||||
data: {
|
||||
error,
|
||||
success: false,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
Lbryio.call('file', 'list_blocked', {
|
||||
auth_token: '',
|
||||
}).then(success, failure);
|
||||
};
|
||||
}
|
||||
|
||||
export function doBlackListedOutpointsSubscribe() {
|
||||
return dispatch => {
|
||||
dispatch(doFetchBlackListedOutpoints());
|
||||
setInterval(() => dispatch(doFetchBlackListedOutpoints()), CHECK_BLACK_LISTED_CONTENT_INTERVAL);
|
||||
};
|
||||
}
|
35
extras/lbryinc/redux/actions/cost_info.js
Normal file
35
extras/lbryinc/redux/actions/cost_info.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
import * as ACTIONS from 'constants/action_types';
|
||||
import { Lbryio } from 'lbryinc';
|
||||
import { selectClaimForUri } from 'redux/selectors/claims';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export function doFetchCostInfoForUri(uri) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const claim = selectClaimForUri(state, uri);
|
||||
|
||||
if (!claim) return;
|
||||
|
||||
function resolve(costInfo) {
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_COST_INFO_COMPLETED,
|
||||
data: {
|
||||
uri,
|
||||
costInfo,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const fee = claim.value ? claim.value.fee : undefined;
|
||||
|
||||
if (fee === undefined) {
|
||||
resolve({ cost: 0, includesData: true });
|
||||
} else if (fee.currency === 'LBC') {
|
||||
resolve({ cost: fee.amount, includesData: true });
|
||||
} else {
|
||||
Lbryio.getExchangeRates().then(({ LBC_USD }) => {
|
||||
resolve({ cost: fee.amount / LBC_USD, includesData: true });
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
47
extras/lbryinc/redux/actions/filtered.js
Normal file
47
extras/lbryinc/redux/actions/filtered.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { Lbryio } from 'lbryinc';
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
|
||||
const CHECK_FILTERED_CONTENT_INTERVAL = 60 * 60 * 1000;
|
||||
|
||||
export function doFetchFilteredOutpoints() {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_FILTERED_CONTENT_STARTED,
|
||||
});
|
||||
|
||||
const success = ({ outpoints }) => {
|
||||
let formattedOutpoints = [];
|
||||
if (outpoints) {
|
||||
formattedOutpoints = outpoints.map(outpoint => {
|
||||
const [txid, nout] = outpoint.split(':');
|
||||
return { txid, nout: Number.parseInt(nout, 10) };
|
||||
});
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_FILTERED_CONTENT_COMPLETED,
|
||||
data: {
|
||||
outpoints: formattedOutpoints,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const failure = ({ error }) => {
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_FILTERED_CONTENT_FAILED,
|
||||
data: {
|
||||
error,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
Lbryio.call('file', 'list_filtered', { auth_token: '' }).then(success, failure);
|
||||
};
|
||||
}
|
||||
|
||||
export function doFilteredOutpointsSubscribe() {
|
||||
return dispatch => {
|
||||
dispatch(doFetchFilteredOutpoints());
|
||||
setInterval(() => dispatch(doFetchFilteredOutpoints()), CHECK_FILTERED_CONTENT_INTERVAL);
|
||||
};
|
||||
}
|
32
extras/lbryinc/redux/actions/stats.js
Normal file
32
extras/lbryinc/redux/actions/stats.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
// @flow
|
||||
import { Lbryio } from 'lbryinc';
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
|
||||
export const doFetchViewCount = (claimIdCsv: string) => (dispatch: Dispatch) => {
|
||||
dispatch({ type: ACTIONS.FETCH_VIEW_COUNT_STARTED });
|
||||
|
||||
return Lbryio.call('file', 'view_count', { claim_id: claimIdCsv })
|
||||
.then((result: Array<number>) => {
|
||||
const viewCounts = result;
|
||||
dispatch({ type: ACTIONS.FETCH_VIEW_COUNT_COMPLETED, data: { claimIdCsv, viewCounts } });
|
||||
})
|
||||
.catch(error => {
|
||||
dispatch({ type: ACTIONS.FETCH_VIEW_COUNT_FAILED, data: error });
|
||||
});
|
||||
};
|
||||
|
||||
export const doFetchSubCount = (claimId: string) => (dispatch: Dispatch) => {
|
||||
dispatch({ type: ACTIONS.FETCH_SUB_COUNT_STARTED });
|
||||
|
||||
return Lbryio.call('subscription', 'sub_count', { claim_id: claimId })
|
||||
.then((result: Array<number>) => {
|
||||
const subCount = result[0];
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_SUB_COUNT_COMPLETED,
|
||||
data: { claimId, subCount },
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
dispatch({ type: ACTIONS.FETCH_SUB_COUNT_FAILED, data: error });
|
||||
});
|
||||
};
|
289
extras/lbryinc/redux/actions/sync.js
Normal file
289
extras/lbryinc/redux/actions/sync.js
Normal file
|
@ -0,0 +1,289 @@
|
|||
import * as ACTIONS from 'constants/action_types';
|
||||
import { Lbryio } from 'lbryinc';
|
||||
import Lbry from 'lbry';
|
||||
import { doWalletEncrypt, doWalletDecrypt } from 'redux/actions/wallet';
|
||||
|
||||
const NO_WALLET_ERROR = 'no wallet found for this user';
|
||||
|
||||
export function doSetDefaultAccount(success, failure) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: ACTIONS.SET_DEFAULT_ACCOUNT,
|
||||
});
|
||||
|
||||
Lbry.account_list()
|
||||
.then(accountList => {
|
||||
const { lbc_mainnet: accounts } = accountList;
|
||||
let defaultId;
|
||||
for (let i = 0; i < accounts.length; ++i) {
|
||||
if (accounts[i].satoshis > 0) {
|
||||
defaultId = accounts[i].id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// In a case where there's no balance on either account
|
||||
// assume the second (which is created after sync) as default
|
||||
if (!defaultId && accounts.length > 1) {
|
||||
defaultId = accounts[1].id;
|
||||
}
|
||||
|
||||
// Set the default account
|
||||
if (defaultId) {
|
||||
Lbry.account_set({ account_id: defaultId, default: true })
|
||||
.then(() => {
|
||||
if (success) {
|
||||
success();
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
if (failure) {
|
||||
failure(err);
|
||||
}
|
||||
});
|
||||
} else if (failure) {
|
||||
// no default account to set
|
||||
failure('Could not set a default account'); // fail
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
if (failure) {
|
||||
failure(err);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doSetSync(oldHash, newHash, data) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: ACTIONS.SET_SYNC_STARTED,
|
||||
});
|
||||
|
||||
return Lbryio.call('sync', 'set', { old_hash: oldHash, new_hash: newHash, data }, 'post')
|
||||
.then(response => {
|
||||
if (!response.hash) {
|
||||
throw Error('No hash returned for sync/set.');
|
||||
}
|
||||
|
||||
return dispatch({
|
||||
type: ACTIONS.SET_SYNC_COMPLETED,
|
||||
data: { syncHash: response.hash },
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
dispatch({
|
||||
type: ACTIONS.SET_SYNC_FAILED,
|
||||
data: { error },
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doGetSync(passedPassword, callback) {
|
||||
const password = passedPassword === null || passedPassword === undefined ? '' : passedPassword;
|
||||
|
||||
function handleCallback(error, hasNewData) {
|
||||
if (callback) {
|
||||
if (typeof callback !== 'function') {
|
||||
throw new Error('Second argument passed to "doGetSync" must be a function');
|
||||
}
|
||||
|
||||
callback(error, hasNewData);
|
||||
}
|
||||
}
|
||||
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: ACTIONS.GET_SYNC_STARTED,
|
||||
});
|
||||
|
||||
const data = {};
|
||||
|
||||
Lbry.wallet_status()
|
||||
.then(status => {
|
||||
if (status.is_locked) {
|
||||
return Lbry.wallet_unlock({ password });
|
||||
}
|
||||
|
||||
// Wallet is already unlocked
|
||||
return true;
|
||||
})
|
||||
.then(isUnlocked => {
|
||||
if (isUnlocked) {
|
||||
return Lbry.sync_hash();
|
||||
}
|
||||
data.unlockFailed = true;
|
||||
throw new Error();
|
||||
})
|
||||
.then(hash => Lbryio.call('sync', 'get', { hash }, 'post'))
|
||||
.then(response => {
|
||||
const syncHash = response.hash;
|
||||
data.syncHash = syncHash;
|
||||
data.syncData = response.data;
|
||||
data.changed = response.changed;
|
||||
data.hasSyncedWallet = true;
|
||||
|
||||
if (response.changed) {
|
||||
return Lbry.sync_apply({ password, data: response.data, blocking: true });
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
if (!response) {
|
||||
dispatch({ type: ACTIONS.GET_SYNC_COMPLETED, data });
|
||||
handleCallback(null, data.changed);
|
||||
return;
|
||||
}
|
||||
|
||||
const { hash: walletHash, data: walletData } = response;
|
||||
|
||||
if (walletHash !== data.syncHash) {
|
||||
// different local hash, need to synchronise
|
||||
dispatch(doSetSync(data.syncHash, walletHash, walletData));
|
||||
}
|
||||
|
||||
dispatch({ type: ACTIONS.GET_SYNC_COMPLETED, data });
|
||||
handleCallback(null, data.changed);
|
||||
})
|
||||
.catch(syncAttemptError => {
|
||||
if (data.unlockFailed) {
|
||||
dispatch({ type: ACTIONS.GET_SYNC_FAILED, data: { error: syncAttemptError } });
|
||||
|
||||
if (password !== '') {
|
||||
dispatch({ type: ACTIONS.SYNC_APPLY_BAD_PASSWORD });
|
||||
}
|
||||
|
||||
handleCallback(syncAttemptError);
|
||||
} else if (data.hasSyncedWallet) {
|
||||
const error =
|
||||
(syncAttemptError && syncAttemptError.message) || 'Error getting synced wallet';
|
||||
dispatch({
|
||||
type: ACTIONS.GET_SYNC_FAILED,
|
||||
data: {
|
||||
error,
|
||||
},
|
||||
});
|
||||
|
||||
// Temp solution until we have a bad password error code
|
||||
// Don't fail on blank passwords so we don't show a "password error" message
|
||||
// before users have ever entered a password
|
||||
if (password !== '') {
|
||||
dispatch({ type: ACTIONS.SYNC_APPLY_BAD_PASSWORD });
|
||||
}
|
||||
|
||||
handleCallback(error);
|
||||
} else {
|
||||
// user doesn't have a synced wallet
|
||||
dispatch({
|
||||
type: ACTIONS.GET_SYNC_COMPLETED,
|
||||
data: { hasSyncedWallet: false, syncHash: null },
|
||||
});
|
||||
|
||||
// call sync_apply to get data to sync
|
||||
// first time sync. use any string for old hash
|
||||
if (syncAttemptError.message === NO_WALLET_ERROR) {
|
||||
Lbry.sync_apply({ password })
|
||||
.then(({ hash: walletHash, data: syncApplyData }) => {
|
||||
dispatch(doSetSync('', walletHash, syncApplyData, password));
|
||||
handleCallback();
|
||||
})
|
||||
.catch(syncApplyError => {
|
||||
handleCallback(syncApplyError);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doSyncApply(syncHash, syncData, password) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: ACTIONS.SYNC_APPLY_STARTED,
|
||||
});
|
||||
|
||||
Lbry.sync_apply({ password, data: syncData })
|
||||
.then(({ hash: walletHash, data: walletData }) => {
|
||||
dispatch({
|
||||
type: ACTIONS.SYNC_APPLY_COMPLETED,
|
||||
});
|
||||
|
||||
if (walletHash !== syncHash) {
|
||||
// different local hash, need to synchronise
|
||||
dispatch(doSetSync(syncHash, walletHash, walletData));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch({
|
||||
type: ACTIONS.SYNC_APPLY_FAILED,
|
||||
data: {
|
||||
error:
|
||||
'Invalid password specified. Please enter the password for your previously synchronised wallet.',
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doCheckSync() {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: ACTIONS.GET_SYNC_STARTED,
|
||||
});
|
||||
|
||||
Lbry.sync_hash().then(hash => {
|
||||
Lbryio.call('sync', 'get', { hash }, 'post')
|
||||
.then(response => {
|
||||
const data = {
|
||||
hasSyncedWallet: true,
|
||||
syncHash: response.hash,
|
||||
syncData: response.data,
|
||||
hashChanged: response.changed,
|
||||
};
|
||||
dispatch({ type: ACTIONS.GET_SYNC_COMPLETED, data });
|
||||
})
|
||||
.catch(() => {
|
||||
// user doesn't have a synced wallet
|
||||
dispatch({
|
||||
type: ACTIONS.GET_SYNC_COMPLETED,
|
||||
data: { hasSyncedWallet: false, syncHash: null },
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doResetSync() {
|
||||
return dispatch =>
|
||||
new Promise(resolve => {
|
||||
dispatch({ type: ACTIONS.SYNC_RESET });
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
export function doSyncEncryptAndDecrypt(oldPassword, newPassword, encrypt) {
|
||||
return dispatch => {
|
||||
const data = {};
|
||||
return Lbry.sync_hash()
|
||||
.then(hash => Lbryio.call('sync', 'get', { hash }, 'post'))
|
||||
.then(syncGetResponse => {
|
||||
data.oldHash = syncGetResponse.hash;
|
||||
|
||||
return Lbry.sync_apply({ password: oldPassword, data: syncGetResponse.data });
|
||||
})
|
||||
.then(() => {
|
||||
if (encrypt) {
|
||||
dispatch(doWalletEncrypt(newPassword));
|
||||
} else {
|
||||
dispatch(doWalletDecrypt());
|
||||
}
|
||||
})
|
||||
.then(() => Lbry.sync_apply({ password: newPassword }))
|
||||
.then(syncApplyResponse => {
|
||||
if (syncApplyResponse.hash !== data.oldHash) {
|
||||
return dispatch(doSetSync(data.oldHash, syncApplyResponse.hash, syncApplyResponse.data));
|
||||
}
|
||||
})
|
||||
.catch(console.error);
|
||||
};
|
||||
}
|
29
extras/lbryinc/redux/reducers/auth.js
Normal file
29
extras/lbryinc/redux/reducers/auth.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import * as ACTIONS from 'constants/action_types';
|
||||
|
||||
const reducers = {};
|
||||
const defaultState = {
|
||||
authenticating: false,
|
||||
};
|
||||
|
||||
reducers[ACTIONS.GENERATE_AUTH_TOKEN_FAILURE] = state =>
|
||||
Object.assign({}, state, {
|
||||
authToken: null,
|
||||
authenticating: false,
|
||||
});
|
||||
|
||||
reducers[ACTIONS.GENERATE_AUTH_TOKEN_STARTED] = state =>
|
||||
Object.assign({}, state, {
|
||||
authenticating: true,
|
||||
});
|
||||
|
||||
reducers[ACTIONS.GENERATE_AUTH_TOKEN_SUCCESS] = (state, action) =>
|
||||
Object.assign({}, state, {
|
||||
authToken: action.data.authToken,
|
||||
authenticating: false,
|
||||
});
|
||||
|
||||
export function authReducer(state = defaultState, action) {
|
||||
const handler = reducers[action.type];
|
||||
if (handler) return handler(state, action);
|
||||
return state;
|
||||
}
|
37
extras/lbryinc/redux/reducers/blacklist.js
Normal file
37
extras/lbryinc/redux/reducers/blacklist.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
import * as ACTIONS from 'constants/action_types';
|
||||
import { handleActions } from 'util/redux-utils';
|
||||
|
||||
const defaultState = {
|
||||
fetchingBlackListedOutpoints: false,
|
||||
fetchingBlackListedOutpointsSucceed: undefined,
|
||||
blackListedOutpoints: undefined,
|
||||
};
|
||||
|
||||
export const blacklistReducer = handleActions(
|
||||
{
|
||||
[ACTIONS.FETCH_BLACK_LISTED_CONTENT_STARTED]: state => ({
|
||||
...state,
|
||||
fetchingBlackListedOutpoints: true,
|
||||
}),
|
||||
[ACTIONS.FETCH_BLACK_LISTED_CONTENT_COMPLETED]: (state, action) => {
|
||||
const { outpoints, success } = action.data;
|
||||
return {
|
||||
...state,
|
||||
fetchingBlackListedOutpoints: false,
|
||||
fetchingBlackListedOutpointsSucceed: success,
|
||||
blackListedOutpoints: outpoints,
|
||||
};
|
||||
},
|
||||
[ACTIONS.FETCH_BLACK_LISTED_CONTENT_FAILED]: (state, action) => {
|
||||
const { error, success } = action.data;
|
||||
|
||||
return {
|
||||
...state,
|
||||
fetchingBlackListedOutpoints: false,
|
||||
fetchingBlackListedOutpointsSucceed: success,
|
||||
fetchingBlackListedOutpointsError: error,
|
||||
};
|
||||
},
|
||||
},
|
||||
defaultState
|
||||
);
|
38
extras/lbryinc/redux/reducers/cost_info.js
Normal file
38
extras/lbryinc/redux/reducers/cost_info.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { handleActions } from 'util/redux-utils';
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
|
||||
const defaultState = {
|
||||
fetching: {},
|
||||
byUri: {},
|
||||
};
|
||||
|
||||
export const costInfoReducer = handleActions(
|
||||
{
|
||||
[ACTIONS.FETCH_COST_INFO_STARTED]: (state, action) => {
|
||||
const { uri } = action.data;
|
||||
const newFetching = Object.assign({}, state.fetching);
|
||||
newFetching[uri] = true;
|
||||
|
||||
return {
|
||||
...state,
|
||||
fetching: newFetching,
|
||||
};
|
||||
},
|
||||
|
||||
[ACTIONS.FETCH_COST_INFO_COMPLETED]: (state, action) => {
|
||||
const { uri, costInfo } = action.data;
|
||||
const newByUri = Object.assign({}, state.byUri);
|
||||
const newFetching = Object.assign({}, state.fetching);
|
||||
|
||||
newByUri[uri] = costInfo;
|
||||
delete newFetching[uri];
|
||||
|
||||
return {
|
||||
...state,
|
||||
byUri: newByUri,
|
||||
fetching: newFetching,
|
||||
};
|
||||
},
|
||||
},
|
||||
defaultState
|
||||
);
|
34
extras/lbryinc/redux/reducers/filtered.js
Normal file
34
extras/lbryinc/redux/reducers/filtered.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
import * as ACTIONS from 'constants/action_types';
|
||||
import { handleActions } from 'util/redux-utils';
|
||||
|
||||
const defaultState = {
|
||||
loading: false,
|
||||
filteredOutpoints: undefined,
|
||||
};
|
||||
|
||||
export const filteredReducer = handleActions(
|
||||
{
|
||||
[ACTIONS.FETCH_FILTERED_CONTENT_STARTED]: state => ({
|
||||
...state,
|
||||
loading: true,
|
||||
}),
|
||||
[ACTIONS.FETCH_FILTERED_CONTENT_COMPLETED]: (state, action) => {
|
||||
const { outpoints } = action.data;
|
||||
return {
|
||||
...state,
|
||||
loading: false,
|
||||
filteredOutpoints: outpoints,
|
||||
};
|
||||
},
|
||||
[ACTIONS.FETCH_FILTERED_CONTENT_FAILED]: (state, action) => {
|
||||
const { error } = action.data;
|
||||
|
||||
return {
|
||||
...state,
|
||||
loading: false,
|
||||
fetchingFilteredOutpointsError: error,
|
||||
};
|
||||
},
|
||||
},
|
||||
defaultState
|
||||
);
|
55
extras/lbryinc/redux/reducers/stats.js
Normal file
55
extras/lbryinc/redux/reducers/stats.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { handleActions } from 'util/redux-utils';
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
|
||||
const defaultState = {
|
||||
fetchingViewCount: false,
|
||||
viewCountError: undefined,
|
||||
viewCountById: {},
|
||||
fetchingSubCount: false,
|
||||
subCountError: undefined,
|
||||
subCountById: {},
|
||||
};
|
||||
|
||||
export const statsReducer = handleActions(
|
||||
{
|
||||
[ACTIONS.FETCH_VIEW_COUNT_STARTED]: state => ({ ...state, fetchingViewCount: true }),
|
||||
[ACTIONS.FETCH_VIEW_COUNT_FAILED]: (state, action) => ({
|
||||
...state,
|
||||
viewCountError: action.data,
|
||||
}),
|
||||
[ACTIONS.FETCH_VIEW_COUNT_COMPLETED]: (state, action) => {
|
||||
const { claimIdCsv, viewCounts } = action.data;
|
||||
|
||||
const viewCountById = Object.assign({}, state.viewCountById);
|
||||
const claimIds = claimIdCsv.split(',');
|
||||
|
||||
if (claimIds.length === viewCounts.length) {
|
||||
claimIds.forEach((claimId, index) => {
|
||||
viewCountById[claimId] = viewCounts[index];
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
fetchingViewCount: false,
|
||||
viewCountById,
|
||||
};
|
||||
},
|
||||
[ACTIONS.FETCH_SUB_COUNT_STARTED]: state => ({ ...state, fetchingSubCount: true }),
|
||||
[ACTIONS.FETCH_SUB_COUNT_FAILED]: (state, action) => ({
|
||||
...state,
|
||||
subCountError: action.data,
|
||||
}),
|
||||
[ACTIONS.FETCH_SUB_COUNT_COMPLETED]: (state, action) => {
|
||||
const { claimId, subCount } = action.data;
|
||||
|
||||
const subCountById = { ...state.subCountById, [claimId]: subCount };
|
||||
return {
|
||||
...state,
|
||||
fetchingSubCount: false,
|
||||
subCountById,
|
||||
};
|
||||
},
|
||||
},
|
||||
defaultState
|
||||
);
|
89
extras/lbryinc/redux/reducers/sync.js
Normal file
89
extras/lbryinc/redux/reducers/sync.js
Normal file
|
@ -0,0 +1,89 @@
|
|||
import * as ACTIONS from 'constants/action_types';
|
||||
|
||||
const reducers = {};
|
||||
const defaultState = {
|
||||
hasSyncedWallet: false,
|
||||
syncHash: null,
|
||||
syncData: null,
|
||||
setSyncErrorMessage: null,
|
||||
getSyncErrorMessage: null,
|
||||
syncApplyErrorMessage: '',
|
||||
syncApplyIsPending: false,
|
||||
syncApplyPasswordError: false,
|
||||
getSyncIsPending: false,
|
||||
setSyncIsPending: false,
|
||||
hashChanged: false,
|
||||
};
|
||||
|
||||
reducers[ACTIONS.GET_SYNC_STARTED] = state =>
|
||||
Object.assign({}, state, {
|
||||
getSyncIsPending: true,
|
||||
getSyncErrorMessage: null,
|
||||
});
|
||||
|
||||
reducers[ACTIONS.GET_SYNC_COMPLETED] = (state, action) =>
|
||||
Object.assign({}, state, {
|
||||
syncHash: action.data.syncHash,
|
||||
syncData: action.data.syncData,
|
||||
hasSyncedWallet: action.data.hasSyncedWallet,
|
||||
getSyncIsPending: false,
|
||||
hashChanged: action.data.hashChanged,
|
||||
});
|
||||
|
||||
reducers[ACTIONS.GET_SYNC_FAILED] = (state, action) =>
|
||||
Object.assign({}, state, {
|
||||
getSyncIsPending: false,
|
||||
getSyncErrorMessage: action.data.error,
|
||||
});
|
||||
|
||||
reducers[ACTIONS.SET_SYNC_STARTED] = state =>
|
||||
Object.assign({}, state, {
|
||||
setSyncIsPending: true,
|
||||
setSyncErrorMessage: null,
|
||||
});
|
||||
|
||||
reducers[ACTIONS.SET_SYNC_FAILED] = (state, action) =>
|
||||
Object.assign({}, state, {
|
||||
setSyncIsPending: false,
|
||||
setSyncErrorMessage: action.data.error,
|
||||
});
|
||||
|
||||
reducers[ACTIONS.SET_SYNC_COMPLETED] = (state, action) =>
|
||||
Object.assign({}, state, {
|
||||
setSyncIsPending: false,
|
||||
setSyncErrorMessage: null,
|
||||
hasSyncedWallet: true, // sync was successful, so the user has a synced wallet at this point
|
||||
syncHash: action.data.syncHash,
|
||||
});
|
||||
|
||||
reducers[ACTIONS.SYNC_APPLY_STARTED] = state =>
|
||||
Object.assign({}, state, {
|
||||
syncApplyPasswordError: false,
|
||||
syncApplyIsPending: true,
|
||||
syncApplyErrorMessage: '',
|
||||
});
|
||||
|
||||
reducers[ACTIONS.SYNC_APPLY_COMPLETED] = state =>
|
||||
Object.assign({}, state, {
|
||||
syncApplyIsPending: false,
|
||||
syncApplyErrorMessage: '',
|
||||
});
|
||||
|
||||
reducers[ACTIONS.SYNC_APPLY_FAILED] = (state, action) =>
|
||||
Object.assign({}, state, {
|
||||
syncApplyIsPending: false,
|
||||
syncApplyErrorMessage: action.data.error,
|
||||
});
|
||||
|
||||
reducers[ACTIONS.SYNC_APPLY_BAD_PASSWORD] = state =>
|
||||
Object.assign({}, state, {
|
||||
syncApplyPasswordError: true,
|
||||
});
|
||||
|
||||
reducers[ACTIONS.SYNC_RESET] = () => defaultState;
|
||||
|
||||
export function syncReducer(state = defaultState, action) {
|
||||
const handler = reducers[action.type];
|
||||
if (handler) return handler(state, action);
|
||||
return state;
|
||||
}
|
7
extras/lbryinc/redux/selectors/auth.js
Normal file
7
extras/lbryinc/redux/selectors/auth.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { createSelector } from 'reselect';
|
||||
|
||||
const selectState = state => state.auth || {};
|
||||
|
||||
export const selectAuthToken = createSelector(selectState, state => state.authToken);
|
||||
|
||||
export const selectIsAuthenticating = createSelector(selectState, state => state.authenticating);
|
73
extras/lbryinc/redux/selectors/ban.js
Normal file
73
extras/lbryinc/redux/selectors/ban.js
Normal file
|
@ -0,0 +1,73 @@
|
|||
// @flow
|
||||
|
||||
// TODO: This should be in 'redux/selectors/claim.js'. Temporarily putting it
|
||||
// here to get past importing issues with 'lbryinc', which the real fix might
|
||||
// involve moving it from 'extras' to 'ui' (big change).
|
||||
|
||||
import { createCachedSelector } from 're-reselect';
|
||||
import { selectClaimForUri, makeSelectIsBlacklisted } from 'redux/selectors/claims';
|
||||
import { selectMutedChannels } from 'redux/selectors/blocked';
|
||||
import { selectModerationBlockList } from 'redux/selectors/comments';
|
||||
import { selectBlacklistedOutpointMap, selectFilteredOutpointMap } from 'lbryinc';
|
||||
import { getChannelFromClaim } from 'util/claim';
|
||||
import { isURIEqual } from 'util/lbryURI';
|
||||
|
||||
export const selectBanStateForUri = createCachedSelector(
|
||||
selectClaimForUri,
|
||||
selectBlacklistedOutpointMap,
|
||||
selectFilteredOutpointMap,
|
||||
selectMutedChannels,
|
||||
selectModerationBlockList,
|
||||
(state, uri) => makeSelectIsBlacklisted(uri)(state),
|
||||
(claim, blackListedOutpointMap, filteredOutpointMap, mutedChannelUris, personalBlocklist, isBlacklisted) => {
|
||||
const banState = {};
|
||||
|
||||
if (!claim) {
|
||||
return banState;
|
||||
}
|
||||
|
||||
const channelClaim = getChannelFromClaim(claim);
|
||||
|
||||
if (isBlacklisted) {
|
||||
banState['blacklisted'] = true;
|
||||
}
|
||||
|
||||
// This will be replaced once blocking is done at the wallet server level.
|
||||
if (blackListedOutpointMap) {
|
||||
if (
|
||||
(channelClaim && blackListedOutpointMap[`${channelClaim.txid}:${channelClaim.nout}`]) ||
|
||||
blackListedOutpointMap[`${claim.txid}:${claim.nout}`]
|
||||
) {
|
||||
banState['blacklisted'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// We're checking to see if the stream outpoint or signing channel outpoint
|
||||
// is in the filter list.
|
||||
if (filteredOutpointMap) {
|
||||
if (
|
||||
(channelClaim && filteredOutpointMap[`${channelClaim.txid}:${channelClaim.nout}`]) ||
|
||||
filteredOutpointMap[`${claim.txid}:${claim.nout}`]
|
||||
) {
|
||||
banState['filtered'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// block stream claims
|
||||
// block channel claims if we can't control for them in claim search
|
||||
if (mutedChannelUris.length && channelClaim) {
|
||||
if (mutedChannelUris.some((blockedUri) => isURIEqual(blockedUri, channelClaim.permanent_url))) {
|
||||
banState['muted'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Commentron blocklist
|
||||
if (personalBlocklist.length && channelClaim) {
|
||||
if (personalBlocklist.some((blockedUri) => isURIEqual(blockedUri, channelClaim.permanent_url))) {
|
||||
banState['blocked'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return banState;
|
||||
}
|
||||
)((state, uri) => String(uri));
|
20
extras/lbryinc/redux/selectors/blacklist.js
Normal file
20
extras/lbryinc/redux/selectors/blacklist.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { createSelector } from 'reselect';
|
||||
|
||||
export const selectState = state => state.blacklist || {};
|
||||
|
||||
export const selectBlackListedOutpoints = createSelector(
|
||||
selectState,
|
||||
state => state.blackListedOutpoints
|
||||
);
|
||||
|
||||
export const selectBlacklistedOutpointMap = createSelector(
|
||||
selectBlackListedOutpoints,
|
||||
outpoints =>
|
||||
outpoints
|
||||
? outpoints.reduce((acc, val) => {
|
||||
const outpoint = `${val.txid}:${val.nout}`;
|
||||
acc[outpoint] = 1;
|
||||
return acc;
|
||||
}, {})
|
||||
: {}
|
||||
);
|
16
extras/lbryinc/redux/selectors/cost_info.js
Normal file
16
extras/lbryinc/redux/selectors/cost_info.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
// @flow
|
||||
type State = { costInfo: any };
|
||||
|
||||
export const selectState = (state: State) => state.costInfo || {};
|
||||
export const selectAllCostInfoByUri = (state: State) => selectState(state).byUri;
|
||||
export const selectFetchingCostInfo = (state: State) => selectState(state).fetching;
|
||||
|
||||
export const selectCostInfoForUri = (state: State, uri: string) => {
|
||||
const costInfos = selectAllCostInfoByUri(state);
|
||||
return costInfos && costInfos[uri];
|
||||
};
|
||||
|
||||
export const selectFetchingCostInfoForUri = (state: State, uri: string) => {
|
||||
const fetchingByUri = selectFetchingCostInfo(state);
|
||||
return fetchingByUri && fetchingByUri[uri];
|
||||
};
|
20
extras/lbryinc/redux/selectors/filtered.js
Normal file
20
extras/lbryinc/redux/selectors/filtered.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { createSelector } from 'reselect';
|
||||
|
||||
export const selectState = state => state.filtered || {};
|
||||
|
||||
export const selectFilteredOutpoints = createSelector(
|
||||
selectState,
|
||||
state => state.filteredOutpoints
|
||||
);
|
||||
|
||||
export const selectFilteredOutpointMap = createSelector(
|
||||
selectFilteredOutpoints,
|
||||
outpoints =>
|
||||
outpoints
|
||||
? outpoints.reduce((acc, val) => {
|
||||
const outpoint = `${val.txid}:${val.nout}`;
|
||||
acc[outpoint] = 1;
|
||||
return acc;
|
||||
}, {})
|
||||
: {}
|
||||
);
|
20
extras/lbryinc/redux/selectors/stats.js
Normal file
20
extras/lbryinc/redux/selectors/stats.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
// @flow
|
||||
import { createSelector } from 'reselect';
|
||||
import { selectClaimIdForUri } from 'redux/selectors/claims';
|
||||
|
||||
type State = { claims: any };
|
||||
const selectState = state => state.stats || {};
|
||||
export const selectViewCount = createSelector(selectState, state => state.viewCountById);
|
||||
export const selectSubCount = createSelector(selectState, state => state.subCountById);
|
||||
|
||||
export const selectViewCountForUri = (state: State, uri: string) => {
|
||||
const claimId = selectClaimIdForUri(state, uri);
|
||||
const viewCountById = selectViewCount(state);
|
||||
return claimId ? viewCountById[claimId] || 0 : 0;
|
||||
};
|
||||
|
||||
export const selectSubCountForUri = (state: State, uri: string) => {
|
||||
const claimId = selectClaimIdForUri(state, uri);
|
||||
const subCountById = selectSubCount(state);
|
||||
return claimId ? subCountById[claimId] || 0 : 0;
|
||||
};
|
40
extras/lbryinc/redux/selectors/sync.js
Normal file
40
extras/lbryinc/redux/selectors/sync.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { createSelector } from 'reselect';
|
||||
|
||||
const selectState = state => state.sync || {};
|
||||
|
||||
export const selectHasSyncedWallet = createSelector(selectState, state => state.hasSyncedWallet);
|
||||
|
||||
export const selectSyncHash = createSelector(selectState, state => state.syncHash);
|
||||
|
||||
export const selectSyncData = createSelector(selectState, state => state.syncData);
|
||||
|
||||
export const selectSetSyncErrorMessage = createSelector(
|
||||
selectState,
|
||||
state => state.setSyncErrorMessage
|
||||
);
|
||||
|
||||
export const selectGetSyncErrorMessage = createSelector(
|
||||
selectState,
|
||||
state => state.getSyncErrorMessage
|
||||
);
|
||||
|
||||
export const selectGetSyncIsPending = createSelector(selectState, state => state.getSyncIsPending);
|
||||
|
||||
export const selectSetSyncIsPending = createSelector(selectState, state => state.setSyncIsPending);
|
||||
|
||||
export const selectHashChanged = createSelector(selectState, state => state.hashChanged);
|
||||
|
||||
export const selectSyncApplyIsPending = createSelector(
|
||||
selectState,
|
||||
state => state.syncApplyIsPending
|
||||
);
|
||||
|
||||
export const selectSyncApplyErrorMessage = createSelector(
|
||||
selectState,
|
||||
state => state.syncApplyErrorMessage
|
||||
);
|
||||
|
||||
export const selectSyncApplyPasswordError = createSelector(
|
||||
selectState,
|
||||
state => state.syncApplyPasswordError
|
||||
);
|
17
extras/lbryinc/util/redux-utils-delete-me.js
Normal file
17
extras/lbryinc/util/redux-utils-delete-me.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
// util for creating reducers
|
||||
// based off of redux-actions
|
||||
// https://redux-actions.js.org/docs/api/handleAction.html#handleactions
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const handleActions = (actionMap, defaultState) => (state = defaultState, action) => {
|
||||
const handler = actionMap[action.type];
|
||||
|
||||
if (handler) {
|
||||
const newState = handler(state, action);
|
||||
return Object.assign({}, state, newState);
|
||||
}
|
||||
|
||||
// just return the original state if no handler
|
||||
// returning a copy here breaks redux-persist
|
||||
return state;
|
||||
};
|
10
extras/lbryinc/util/swap-json.js
Normal file
10
extras/lbryinc/util/swap-json.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
export function swapKeyAndValue(dict) {
|
||||
const ret = {};
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const key in dict) {
|
||||
if (dict.hasOwnProperty(key)) {
|
||||
ret[dict[key]] = key;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
78
extras/lbryinc/util/transifex-upload.js
Normal file
78
extras/lbryinc/util/transifex-upload.js
Normal file
|
@ -0,0 +1,78 @@
|
|||
const apiBaseUrl = 'https://www.transifex.com/api/2/project';
|
||||
const resource = 'app-strings';
|
||||
|
||||
export function doTransifexUpload(contents, project, token, success, fail) {
|
||||
const url = `${apiBaseUrl}/${project}/resources/`;
|
||||
const updateUrl = `${apiBaseUrl}/${project}/resource/${resource}/content/`;
|
||||
const headers = {
|
||||
Authorization: `Basic ${Buffer.from(`api:${token}`).toString('base64')}`,
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
const req = {
|
||||
accept_translations: true,
|
||||
i18n_type: 'KEYVALUEJSON',
|
||||
name: resource,
|
||||
slug: resource,
|
||||
content: contents,
|
||||
};
|
||||
|
||||
function handleResponse(text) {
|
||||
let json;
|
||||
try {
|
||||
// transifex api returns Python dicts for some reason.
|
||||
// Any way to get the api to return valid JSON?
|
||||
json = JSON.parse(text);
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
if (success) {
|
||||
success(json || text);
|
||||
}
|
||||
}
|
||||
|
||||
function handleError(err) {
|
||||
if (fail) {
|
||||
fail(err.message ? err.message : 'Could not upload strings resource to Transifex');
|
||||
}
|
||||
}
|
||||
|
||||
// check if the resource exists
|
||||
fetch(updateUrl, { headers })
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
// perform an update
|
||||
fetch(updateUrl, {
|
||||
method: 'PUT',
|
||||
headers,
|
||||
body: JSON.stringify({ content: contents }),
|
||||
})
|
||||
.then(response => {
|
||||
if (response.status !== 200 && response.status !== 201) {
|
||||
throw new Error('failed to update transifex');
|
||||
}
|
||||
|
||||
return response.text();
|
||||
})
|
||||
.then(handleResponse)
|
||||
.catch(handleError);
|
||||
})
|
||||
.catch(() => {
|
||||
// resource doesn't exist, create a fresh resource
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify(req),
|
||||
})
|
||||
.then(response => {
|
||||
if (response.status !== 200 && response.status !== 201) {
|
||||
throw new Error('failed to upload to transifex');
|
||||
}
|
||||
|
||||
return response.text();
|
||||
})
|
||||
.then(handleResponse)
|
||||
.catch(handleError);
|
||||
});
|
||||
}
|
3
extras/recsys/index.js
Normal file
3
extras/recsys/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import Recsys from './recsys';
|
||||
|
||||
export default Recsys;
|
257
extras/recsys/recsys.js
Normal file
257
extras/recsys/recsys.js
Normal file
|
@ -0,0 +1,257 @@
|
|||
import { selectUser } from 'redux/selectors/user';
|
||||
import { makeSelectRecommendedRecsysIdForClaimId } from 'redux/selectors/search';
|
||||
import { v4 as Uuidv4 } from 'uuid';
|
||||
import { parseURI } from 'util/lbryURI';
|
||||
import * as SETTINGS from 'constants/settings';
|
||||
import { makeSelectClaimForUri } from 'redux/selectors/claims';
|
||||
import { selectPlayingUri, selectPrimaryUri } from 'redux/selectors/content';
|
||||
import { makeSelectClientSetting, selectDaemonSettings } from 'redux/selectors/settings';
|
||||
import { history } from 'ui/store';
|
||||
|
||||
const recsysEndpoint = 'https://clickstream.odysee.com/log/video/view';
|
||||
const recsysId = 'lighthouse-v0';
|
||||
|
||||
const getClaimIdsFromUris = (uris) => {
|
||||
return uris
|
||||
? uris.map((uri) => {
|
||||
try {
|
||||
const { claimId } = parseURI(uri);
|
||||
return claimId;
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
: [];
|
||||
};
|
||||
|
||||
const recsys = {
|
||||
entries: {},
|
||||
debug: false,
|
||||
/**
|
||||
* Provides for creating, updating, and sending Clickstream data object Entries.
|
||||
* Entries are Created either when recommendedContent loads, or when recommendedContent is clicked.
|
||||
* If recommended content is clicked, An Entry with parentUuid is created.
|
||||
* On page load, find an empty entry with your claimId, or create a new entry and record to it.
|
||||
* The entry will be populated with the following:
|
||||
* - parentUuid // optional
|
||||
* - Uuid
|
||||
* - claimId
|
||||
* - recommendedClaims [] // optionally empty
|
||||
* - playerEvents [] // optionally empty
|
||||
* - recommendedClaimsIndexClicked [] // optionally empty
|
||||
* - UserId
|
||||
* - pageLoadedAt
|
||||
* - isEmbed
|
||||
* - pageExitedAt
|
||||
* - recsysId // optional
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function: onClickedRecommended()
|
||||
* Called when RecommendedContent was clicked.
|
||||
* Adds index of clicked recommendation to parent entry
|
||||
* Adds new Entry with parentUuid for destination page
|
||||
* @param parentClaimId: string,
|
||||
* @param newClaimId: string,
|
||||
*/
|
||||
onClickedRecommended: function (parentClaimId, newClaimId) {
|
||||
const parentEntry = recsys.entries[parentClaimId] ? recsys.entries[parentClaimId] : null;
|
||||
const parentUuid = parentEntry['uuid'];
|
||||
const parentRecommendedClaims = parentEntry['recClaimIds'] || [];
|
||||
const parentClickedIndexes = parentEntry['recClickedVideoIdx'] || [];
|
||||
const indexClicked = parentRecommendedClaims.indexOf(newClaimId);
|
||||
|
||||
if (parentUuid) {
|
||||
recsys.createRecsysEntry(newClaimId, parentUuid);
|
||||
}
|
||||
parentClickedIndexes.push(indexClicked);
|
||||
recsys.log('onClickedRecommended', { parentClaimId, newClaimId });
|
||||
},
|
||||
|
||||
/**
|
||||
* Page was loaded. Get or Create entry and populate it with default data, plus recommended content, recsysId, etc.
|
||||
* Called from recommendedContent component
|
||||
*/
|
||||
onRecsLoaded: function (claimId, uris) {
|
||||
if (window.store) {
|
||||
const state = window.store.getState();
|
||||
if (!recsys.entries[claimId]) {
|
||||
recsys.createRecsysEntry(claimId);
|
||||
}
|
||||
const claimIds = getClaimIdsFromUris(uris);
|
||||
recsys.entries[claimId]['recsysId'] = makeSelectRecommendedRecsysIdForClaimId(claimId)(state) || recsysId;
|
||||
recsys.entries[claimId]['pageLoadedAt'] = Date.now();
|
||||
recsys.entries[claimId]['recClaimIds'] = claimIds;
|
||||
}
|
||||
recsys.log('onRecsLoaded', claimId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates an Entry with optional parentUuid
|
||||
* @param: claimId: string
|
||||
* @param: parentUuid: string (optional)
|
||||
*/
|
||||
createRecsysEntry: function (claimId, parentUuid) {
|
||||
if (window.store && claimId) {
|
||||
const state = window.store.getState();
|
||||
const user = selectUser(state);
|
||||
const userId = user ? user.id : null;
|
||||
if (parentUuid) {
|
||||
// Make a stub entry that will be filled out on page load
|
||||
recsys.entries[claimId] = {
|
||||
uuid: Uuidv4(),
|
||||
parentUuid: parentUuid,
|
||||
uid: userId || null, // selectUser
|
||||
claimId: claimId,
|
||||
recClickedVideoIdx: [],
|
||||
pageLoadedAt: Date.now(),
|
||||
events: [],
|
||||
};
|
||||
} else {
|
||||
recsys.entries[claimId] = {
|
||||
uuid: Uuidv4(),
|
||||
uid: userId, // selectUser
|
||||
claimId: claimId,
|
||||
pageLoadedAt: Date.now(),
|
||||
recsysId: null,
|
||||
recClaimIds: [],
|
||||
recClickedVideoIdx: [],
|
||||
events: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
recsys.log('createRecsysEntry', claimId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Send event for claimId
|
||||
* @param claimId
|
||||
* @param isTentative
|
||||
*/
|
||||
sendRecsysEntry: function (claimId, isTentative) {
|
||||
const shareTelemetry =
|
||||
IS_WEB || (window && window.store && selectDaemonSettings(window.store.getState()).share_usage_data);
|
||||
|
||||
if (recsys.entries[claimId] && shareTelemetry) {
|
||||
const data = JSON.stringify(recsys.entries[claimId]);
|
||||
try {
|
||||
navigator.sendBeacon(recsysEndpoint, data);
|
||||
if (!isTentative) {
|
||||
delete recsys.entries[claimId];
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('no beacon for you', error);
|
||||
}
|
||||
}
|
||||
recsys.log('sendRecsysEntry', claimId);
|
||||
},
|
||||
|
||||
/**
|
||||
* A player event fired. Get the Entry for the claimId, and add the events
|
||||
* @param claimId
|
||||
* @param event
|
||||
*/
|
||||
onRecsysPlayerEvent: function (claimId, event, isEmbedded) {
|
||||
if (!recsys.entries[claimId]) {
|
||||
recsys.createRecsysEntry(claimId);
|
||||
// do something to show it's floating or autoplay
|
||||
}
|
||||
if (isEmbedded) {
|
||||
recsys.entries[claimId]['isEmbed'] = true;
|
||||
}
|
||||
recsys.entries[claimId].events.push(event);
|
||||
recsys.log('onRecsysPlayerEvent', claimId);
|
||||
},
|
||||
log: function (callName, claimId) {
|
||||
if (recsys.debug) {
|
||||
console.log(`Call: ***${callName}***, ClaimId: ${claimId}, Recsys Entries`, Object.assign({}, recsys.entries));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Player closed. Check to see if primaryUri = playingUri
|
||||
* if so, send the Entry.
|
||||
*/
|
||||
onPlayerDispose: function (claimId, isEmbedded) {
|
||||
if (window.store) {
|
||||
const state = window.store.getState();
|
||||
const playingUri = selectPlayingUri(state);
|
||||
const primaryUri = selectPrimaryUri(state);
|
||||
const onFilePage = playingUri === primaryUri;
|
||||
if (!onFilePage || isEmbedded) {
|
||||
if (isEmbedded) {
|
||||
recsys.entries[claimId]['isEmbed'] = true;
|
||||
}
|
||||
recsys.sendRecsysEntry(claimId);
|
||||
}
|
||||
}
|
||||
recsys.log('PlayerDispose', claimId);
|
||||
},
|
||||
|
||||
// /**
|
||||
// * File page unmount or change event
|
||||
// * Check to see if playingUri, floatingEnabled, primaryUri === playingUri
|
||||
// * If not, send the Entry.
|
||||
// * If floating enabled, leaving file page will pop out player, leading to
|
||||
// * more events until player is disposed. Don't send unless floatingPlayer playingUri
|
||||
// */
|
||||
// onLeaveFilePage: function (primaryUri) {
|
||||
// if (window.store) {
|
||||
// const state = window.store.getState();
|
||||
// const claim = makeSelectClaimForUri(primaryUri)(state);
|
||||
// const claimId = claim ? claim.claim_id : null;
|
||||
// const playingUri = selectPlayingUri(state);
|
||||
// const actualPlayingUri = playingUri && playingUri.uri;
|
||||
// // const primaryUri = selectPrimaryUri(state);
|
||||
// const floatingPlayer = makeSelectClientSetting(SETTINGS.FLOATING_PLAYER)(state);
|
||||
// // When leaving page, if floating player is enabled, play will continue.
|
||||
// if (claimId) {
|
||||
// recsys.entries[claimId]['pageExitedAt'] = Date.now();
|
||||
// }
|
||||
// const shouldSend =
|
||||
// (claimId && floatingPlayer && actualPlayingUri && actualPlayingUri !== primaryUri) || !floatingPlayer || !actualPlayingUri;
|
||||
// if (shouldSend) {
|
||||
// recsys.sendRecsysEntry(claimId);
|
||||
// }
|
||||
// recsys.log('LeaveFile', claimId);
|
||||
// }
|
||||
// },
|
||||
|
||||
/**
|
||||
* Navigate event
|
||||
* Send all claimIds that aren't currently playing.
|
||||
*/
|
||||
onNavigate: function () {
|
||||
if (window.store) {
|
||||
const state = window.store.getState();
|
||||
const playingUri = selectPlayingUri(state);
|
||||
const actualPlayingUri = playingUri && playingUri.uri;
|
||||
const claim = makeSelectClaimForUri(actualPlayingUri)(state);
|
||||
const playingClaimId = claim ? claim.claim_id : null;
|
||||
// const primaryUri = selectPrimaryUri(state);
|
||||
const floatingPlayer = makeSelectClientSetting(SETTINGS.FLOATING_PLAYER)(state);
|
||||
// When leaving page, if floating player is enabled, play will continue.
|
||||
Object.keys(recsys.entries).forEach((claimId) => {
|
||||
const shouldSkip = recsys.entries[claimId].parentUuid && !recsys.entries[claimId].recClaimIds;
|
||||
if (!shouldSkip && ((claimId !== playingClaimId && floatingPlayer) || !floatingPlayer)) {
|
||||
recsys.entries[claimId]['pageExitedAt'] = Date.now();
|
||||
recsys.sendRecsysEntry(claimId);
|
||||
}
|
||||
recsys.log('OnNavigate', claimId);
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
// @if TARGET='web'
|
||||
document.addEventListener('visibilitychange', function logData() {
|
||||
if (document.visibilityState === 'hidden') {
|
||||
Object.keys(recsys.entries).map((claimId) => recsys.sendRecsysEntry(claimId, true));
|
||||
}
|
||||
});
|
||||
// @endif
|
||||
|
||||
history.listen(() => {
|
||||
recsys.onNavigate();
|
||||
});
|
||||
|
||||
export default recsys;
|
10
flow-typed/Blocklist.js
vendored
Normal file
10
flow-typed/Blocklist.js
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
declare type BlocklistState = {
|
||||
blockedChannels: Array<string>
|
||||
};
|
||||
|
||||
declare type BlocklistAction = {
|
||||
type: string,
|
||||
data: {
|
||||
uri: string,
|
||||
},
|
||||
};
|
251
flow-typed/Claim.js
vendored
Normal file
251
flow-typed/Claim.js
vendored
Normal file
|
@ -0,0 +1,251 @@
|
|||
// @flow
|
||||
|
||||
declare type Claim = StreamClaim | ChannelClaim | CollectionClaim;
|
||||
|
||||
declare type ChannelClaim = GenericClaim & {
|
||||
value: ChannelMetadata,
|
||||
};
|
||||
|
||||
declare type CollectionClaim = GenericClaim & {
|
||||
value: CollectionMetadata,
|
||||
};
|
||||
|
||||
declare type StreamClaim = GenericClaim & {
|
||||
value: StreamMetadata,
|
||||
};
|
||||
|
||||
declare type GenericClaim = {
|
||||
address: string, // address associated with tx
|
||||
amount: string, // bid amount at time of tx
|
||||
canonical_url: string, // URL with short id, includes channel with short id
|
||||
claim_id: string, // unique claim identifier
|
||||
claim_sequence: number, // not being used currently
|
||||
claim_op: 'create' | 'update',
|
||||
confirmations: number,
|
||||
decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044
|
||||
timestamp?: number, // date of last transaction
|
||||
height: number, // block height the tx was confirmed
|
||||
is_channel_signature_valid?: boolean,
|
||||
is_my_output: boolean,
|
||||
name: string,
|
||||
normalized_name: string, // `name` normalized via unicode NFD spec,
|
||||
nout: number, // index number for an output of a tx
|
||||
permanent_url: string, // name + claim_id
|
||||
short_url: string, // permanent_url with short id, no channel
|
||||
txid: string, // unique tx id
|
||||
type: 'claim' | 'update' | 'support',
|
||||
value_type: 'stream' | 'channel' | 'collection',
|
||||
signing_channel?: ChannelClaim,
|
||||
reposted_claim?: GenericClaim,
|
||||
repost_channel_url?: string,
|
||||
repost_url?: string,
|
||||
repost_bid_amount?: string,
|
||||
purchase_receipt?: PurchaseReceipt,
|
||||
meta: {
|
||||
activation_height: number,
|
||||
claims_in_channel?: number,
|
||||
creation_height: number,
|
||||
creation_timestamp: number,
|
||||
effective_amount: string,
|
||||
expiration_height: number,
|
||||
is_controlling: boolean,
|
||||
support_amount: string,
|
||||
reposted: number,
|
||||
trending_global: number,
|
||||
trending_group: number,
|
||||
trending_local: number,
|
||||
trending_mixed: number,
|
||||
},
|
||||
};
|
||||
|
||||
declare type GenericMetadata = {
|
||||
title?: string,
|
||||
description?: string,
|
||||
thumbnail?: {
|
||||
url?: string,
|
||||
},
|
||||
languages?: Array<string>,
|
||||
tags?: Array<string>,
|
||||
locations?: Array<Location>,
|
||||
};
|
||||
|
||||
declare type ChannelMetadata = GenericMetadata & {
|
||||
public_key: string,
|
||||
public_key_id: string,
|
||||
cover_url?: string,
|
||||
email?: string,
|
||||
website_url?: string,
|
||||
featured?: Array<string>,
|
||||
};
|
||||
|
||||
declare type CollectionMetadata = GenericMetadata & {
|
||||
claims: Array<string>,
|
||||
}
|
||||
|
||||
declare type StreamMetadata = GenericMetadata & {
|
||||
license?: string, // License "title" ex: Creative Commons, Custom copyright
|
||||
license_url?: string, // Link to full license
|
||||
release_time?: number, // linux timestamp
|
||||
author?: string,
|
||||
|
||||
source: {
|
||||
sd_hash: string,
|
||||
media_type?: string,
|
||||
hash?: string,
|
||||
name?: string, // file name
|
||||
size?: number, // size of file in bytes
|
||||
},
|
||||
|
||||
// Only exists if a stream has a fee
|
||||
fee?: Fee,
|
||||
|
||||
stream_type: 'video' | 'audio' | 'image' | 'software',
|
||||
// Below correspond to `stream_type`
|
||||
video?: {
|
||||
duration: number,
|
||||
height: number,
|
||||
width: number,
|
||||
},
|
||||
audio?: {
|
||||
duration: number,
|
||||
},
|
||||
image?: {
|
||||
height: number,
|
||||
width: number,
|
||||
},
|
||||
software?: {
|
||||
os: string,
|
||||
},
|
||||
};
|
||||
|
||||
declare type Location = {
|
||||
latitude?: number,
|
||||
longitude?: number,
|
||||
country?: string,
|
||||
state?: string,
|
||||
city?: string,
|
||||
code?: string,
|
||||
};
|
||||
|
||||
declare type Fee = {
|
||||
amount: string,
|
||||
currency: string,
|
||||
address: string,
|
||||
};
|
||||
|
||||
declare type PurchaseReceipt = {
|
||||
address: string,
|
||||
amount: string,
|
||||
claim_id: string,
|
||||
confirmations: number,
|
||||
height: number,
|
||||
nout: number,
|
||||
timestamp: number,
|
||||
txid: string,
|
||||
type: 'purchase',
|
||||
};
|
||||
|
||||
declare type ClaimErrorCensor = {
|
||||
address: string,
|
||||
amount: string,
|
||||
canonical_url: string,
|
||||
claim_id: string,
|
||||
claim_op: string,
|
||||
confirmations: number,
|
||||
has_signing_key: boolean,
|
||||
height: number,
|
||||
meta: {
|
||||
activation_height: number,
|
||||
claims_in_channel: number,
|
||||
creation_height: number,
|
||||
creation_timestamp: number,
|
||||
effective_amount: string,
|
||||
expiration_height: number,
|
||||
is_controlling: boolean,
|
||||
reposted: number,
|
||||
support_amount: string,
|
||||
take_over_height: number,
|
||||
},
|
||||
name: string,
|
||||
normalized_name: string,
|
||||
nout: number,
|
||||
permanent_url: string,
|
||||
short_url: string,
|
||||
timestamp: number,
|
||||
txid: string,
|
||||
type: string,
|
||||
value: {
|
||||
public_key: string,
|
||||
public_key_id: string,
|
||||
},
|
||||
value_type: string,
|
||||
}
|
||||
|
||||
declare type ClaimActionResolveInfo = {
|
||||
[string]: {
|
||||
stream: ?StreamClaim,
|
||||
channel: ?ChannelClaim,
|
||||
claimsInChannel: ?number,
|
||||
collection: ?CollectionClaim,
|
||||
errorCensor: ?ClaimErrorCensor,
|
||||
},
|
||||
}
|
||||
|
||||
declare type ChannelUpdateParams = {
|
||||
claim_id: string,
|
||||
bid?: string,
|
||||
title?: string,
|
||||
cover_url?: string,
|
||||
thumbnail_url?: string,
|
||||
description?: string,
|
||||
website_url?: string,
|
||||
email?: string,
|
||||
tags?: Array<string>,
|
||||
replace?: boolean,
|
||||
languages?: Array<string>,
|
||||
locations?: Array<string>,
|
||||
blocking?: boolean,
|
||||
}
|
||||
|
||||
declare type ChannelPublishParams = {
|
||||
name: string,
|
||||
bid: string,
|
||||
blocking?: true,
|
||||
title?: string,
|
||||
cover_url?: string,
|
||||
thumbnail_url?: string,
|
||||
description?: string,
|
||||
website_url?: string,
|
||||
email?: string,
|
||||
tags?: Array<string>,
|
||||
languages?: Array<string>,
|
||||
}
|
||||
|
||||
declare type CollectionUpdateParams = {
|
||||
claim_id: string,
|
||||
claim_ids?: Array<string>,
|
||||
bid?: string,
|
||||
title?: string,
|
||||
cover_url?: string,
|
||||
thumbnail_url?: string,
|
||||
description?: string,
|
||||
website_url?: string,
|
||||
email?: string,
|
||||
tags?: Array<string>,
|
||||
replace?: boolean,
|
||||
languages?: Array<string>,
|
||||
locations?: Array<string>,
|
||||
blocking?: boolean,
|
||||
}
|
||||
|
||||
declare type CollectionPublishParams = {
|
||||
name: string,
|
||||
bid: string,
|
||||
claim_ids: Array<string>,
|
||||
blocking?: true,
|
||||
title?: string,
|
||||
thumbnail_url?: string,
|
||||
description?: string,
|
||||
tags?: Array<string>,
|
||||
languages?: Array<string>,
|
||||
}
|
29
flow-typed/CoinSwap.js
vendored
Normal file
29
flow-typed/CoinSwap.js
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
declare type CoinSwapInfo = {
|
||||
chargeCode: string,
|
||||
coins: Array<string>,
|
||||
sendAddresses: { [string]: string},
|
||||
sendAmounts: { [string]: any },
|
||||
lbcAmount: number,
|
||||
status?: {
|
||||
status: string,
|
||||
receiptCurrency: string,
|
||||
receiptTxid: string,
|
||||
lbcTxid: string,
|
||||
},
|
||||
}
|
||||
|
||||
declare type CoinSwapState = {
|
||||
coinSwaps: Array<CoinSwapInfo>,
|
||||
};
|
||||
|
||||
declare type CoinSwapAddAction = {
|
||||
type: string,
|
||||
data: CoinSwapInfo,
|
||||
};
|
||||
|
||||
declare type CoinSwapRemoveAction = {
|
||||
type: string,
|
||||
data: {
|
||||
chargeCode: string,
|
||||
},
|
||||
};
|
33
flow-typed/Collections.js
vendored
Normal file
33
flow-typed/Collections.js
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
declare type Collection = {
|
||||
id: string,
|
||||
items: Array<?string>,
|
||||
name: string,
|
||||
type: string,
|
||||
updatedAt: number,
|
||||
totalItems?: number,
|
||||
sourceId?: string, // if copied, claimId of original collection
|
||||
};
|
||||
|
||||
declare type CollectionState = {
|
||||
unpublished: CollectionGroup,
|
||||
resolved: CollectionGroup,
|
||||
pending: CollectionGroup,
|
||||
edited: CollectionGroup,
|
||||
builtin: CollectionGroup,
|
||||
saved: Array<string>,
|
||||
isResolvingCollectionById: { [string]: boolean },
|
||||
error?: string | null,
|
||||
};
|
||||
|
||||
declare type CollectionGroup = {
|
||||
[string]: Collection,
|
||||
}
|
||||
|
||||
declare type CollectionEditParams = {
|
||||
uris?: Array<string>,
|
||||
remove?: boolean,
|
||||
replace?: boolean,
|
||||
order?: { from: number, to: number },
|
||||
type?: string,
|
||||
name?: string,
|
||||
}
|
270
flow-typed/Comment.js
vendored
270
flow-typed/Comment.js
vendored
|
@ -12,25 +12,63 @@ declare type Comment = {
|
|||
is_channel_signature_valid?: boolean, // whether or not the signature could be validated
|
||||
parent_id?: number, // comment_id of comment this is in reply to
|
||||
is_pinned: boolean,
|
||||
support_amount: number,
|
||||
replies: number, // number of direct replies (i.e. excluding nested replies).
|
||||
is_moderator: boolean,
|
||||
is_creator: boolean,
|
||||
is_global_mod: boolean,
|
||||
is_fiat?: boolean,
|
||||
};
|
||||
|
||||
declare type PerChannelSettings = {
|
||||
words?: Array<string>,
|
||||
comments_enabled?: boolean,
|
||||
min_tip_amount_comment?: number,
|
||||
min_tip_amount_super_chat?: number,
|
||||
slow_mode_min_gap?: number,
|
||||
};
|
||||
|
||||
// todo: relate individual comments to their commentId
|
||||
declare type CommentsState = {
|
||||
commentsByUri: { [string]: string },
|
||||
byId: { [string]: Array<string> },
|
||||
repliesByParentId: { [string]: Array<string> }, // ParentCommentID -> list of reply comments
|
||||
topLevelCommentsById: { [string]: Array<string> }, // ClaimID -> list of top level comments
|
||||
superChatsByUri: { [string]: { totalAmount: number, comments: Array<Comment> } },
|
||||
byId: { [string]: Array<string> }, // ClaimID -> list of fetched comment IDs.
|
||||
totalCommentsById: {}, // ClaimId -> ultimate total (including replies) in commentron.
|
||||
repliesByParentId: { [string]: Array<string> }, // ParentCommentID -> list of fetched replies.
|
||||
repliesTotalPagesByParentId: {}, // ParentCommentID -> total number of reply pages for a parentId in commentron.
|
||||
topLevelCommentsById: { [string]: Array<string> }, // ClaimID -> list of fetched top level comments.
|
||||
topLevelTotalPagesById: { [string]: number }, // ClaimID -> total number of top-level pages in commentron. Based on COMMENT_PAGE_SIZE_TOP_LEVEL.
|
||||
topLevelTotalCommentsById: { [string]: number }, // ClaimID -> total top level comments in commentron.
|
||||
commentById: { [string]: Comment },
|
||||
linkedCommentAncestors: { [string]: Array<string> }, // {"linkedCommentId": ["parentId", "grandParentId", ...]}
|
||||
pinnedCommentsById: {}, // ClaimId -> array of pinned comment IDs
|
||||
isLoading: boolean,
|
||||
isLoadingById: boolean,
|
||||
isLoadingByParentId: { [string]: boolean },
|
||||
isCommenting: boolean,
|
||||
myComments: ?Set<string>,
|
||||
isFetchingReacts: boolean,
|
||||
myReactsByCommentId: any,
|
||||
othersReactsByCommentId: any,
|
||||
myReactsByCommentId: ?{ [string]: Array<string> }, // {"CommentId:MyChannelId": ["like", "dislike", ...]}
|
||||
othersReactsByCommentId: ?{ [string]: { [string]: number } }, // {"CommentId:MyChannelId": {"like": 2, "dislike": 2, ...}}
|
||||
pendingCommentReactions: Array<string>,
|
||||
moderationBlockList: ?Array<string>,
|
||||
moderationBlockList: ?Array<string>, // @KP rename to "personalBlockList"?
|
||||
adminBlockList: ?Array<string>,
|
||||
moderatorBlockList: ?Array<string>,
|
||||
moderatorBlockListDelegatorsMap: {[string]: Array<string>}, // {"blockedUri": ["delegatorUri1", ""delegatorUri2", ...]}
|
||||
fetchingModerationBlockList: boolean,
|
||||
moderationDelegatesById: { [string]: Array<{ channelId: string, channelName: string }> },
|
||||
fetchingModerationDelegates: boolean,
|
||||
moderationDelegatorsById: { [string]: { global: boolean, delegators: { name: string, claimId: string } }},
|
||||
fetchingModerationDelegators: boolean,
|
||||
blockingByUri: {},
|
||||
unBlockingByUri: {},
|
||||
personalTimeoutMap: { [uri: string]: { blockedAt: string, bannedFor: number, banRemaining: number } },
|
||||
adminTimeoutMap: { [uri: string]: { blockedAt: string, bannedFor: number, banRemaining: number } },
|
||||
moderatorTimeoutMap: { [uri: string]: { blockedAt: string, bannedFor: number, banRemaining: number } },
|
||||
togglingForDelegatorMap: {[string]: Array<string>}, // {"blockedUri": ["delegatorUri1", ""delegatorUri2", ...]}
|
||||
settingsByChannelId: { [string]: PerChannelSettings }, // ChannelID -> settings
|
||||
fetchingSettings: boolean,
|
||||
fetchingBlockedWords: boolean,
|
||||
};
|
||||
|
||||
declare type CommentReactParams = {
|
||||
|
@ -41,3 +79,223 @@ declare type CommentReactParams = {
|
|||
clear_types?: string,
|
||||
remove?: boolean,
|
||||
};
|
||||
|
||||
declare type ReactionReactParams = {
|
||||
comment_ids: string,
|
||||
signature?: string,
|
||||
signing_ts?: string,
|
||||
remove?: boolean,
|
||||
clear_types?: string,
|
||||
type: string,
|
||||
channel_id: string,
|
||||
channel_name: string,
|
||||
};
|
||||
|
||||
declare type ReactionReactResponse = {
|
||||
Reactions: { [string]: { [string]: number} },
|
||||
};
|
||||
|
||||
declare type ReactionListParams = {
|
||||
comment_ids: string, // CSV of IDs
|
||||
channel_id?: string,
|
||||
channel_name?: string,
|
||||
signature?: string,
|
||||
signing_ts?: string,
|
||||
types?: string,
|
||||
};
|
||||
|
||||
declare type ReactionListResponse = {
|
||||
my_reactions: Array<MyReactions>,
|
||||
others_reactions: Array<OthersReactions>,
|
||||
};
|
||||
|
||||
declare type CommentListParams = {
|
||||
page: number, // pagination: which page of results
|
||||
page_size: number, // pagination: nr of comments to show in a page (max 200)
|
||||
claim_id?: string, // claim id of claim being commented on
|
||||
channel_name?: string, // signing channel name of claim (enables 'commentsEnabled' check)
|
||||
channel_id?: string, // signing channel claim id of claim (enables 'commentsEnabled' check)
|
||||
author_claim_id?: string, // filters comments to just this author
|
||||
parent_id?: string, // filters comments to those under this thread
|
||||
top_level?: boolean, // filters to only top level comments
|
||||
hidden?: boolean, // if true, will show hidden comments as well
|
||||
sort_by?: number, // @see: ui/constants/comments.js::SORT_BY
|
||||
};
|
||||
|
||||
declare type CommentListResponse = {
|
||||
items: Array<Comment>,
|
||||
page: number,
|
||||
page_size: number,
|
||||
total_items: number, // Grand total for the claim being commented on.
|
||||
total_filtered_items: number, // Total for filtered queries (e.g. top_level=true, parent_id=xxx, etc.).
|
||||
total_pages: number,
|
||||
has_hidden_comments: boolean,
|
||||
};
|
||||
|
||||
declare type CommentByIdParams = {
|
||||
comment_id: string,
|
||||
with_ancestors: boolean,
|
||||
}
|
||||
|
||||
declare type CommentByIdResponse = {
|
||||
item: Comment,
|
||||
items: Comment,
|
||||
ancestors: Array<Comment>,
|
||||
}
|
||||
|
||||
declare type CommentPinParams = {
|
||||
comment_id: string,
|
||||
channel_id: string,
|
||||
channel_name: string,
|
||||
remove?: boolean,
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
}
|
||||
|
||||
declare type CommentPinResponse = {
|
||||
items: Comment, // "items" is an inherited typo to match SDK. Will be "item" in a new version.
|
||||
}
|
||||
|
||||
declare type CommentEditParams = {
|
||||
comment: string,
|
||||
comment_id: string,
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
}
|
||||
|
||||
declare type CommentEditResponse = Comment
|
||||
|
||||
declare type CommentAbandonParams = {
|
||||
comment_id: string,
|
||||
creator_channel_id?: string,
|
||||
creator_channel_name?: string,
|
||||
channel_id?: string,
|
||||
hexdata?: string,
|
||||
};
|
||||
|
||||
declare type CommentCreateParams = {
|
||||
comment: string,
|
||||
claim_id: string,
|
||||
parent_id?: string,
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
support_tx_id?: string,
|
||||
};
|
||||
|
||||
declare type SuperListParams = {};
|
||||
|
||||
declare type SuperListResponse = {
|
||||
page: number,
|
||||
page_size: number,
|
||||
total_pages: number,
|
||||
total_items: number,
|
||||
total_amount: number,
|
||||
items: Array<Comment>,
|
||||
has_hidden_comments: boolean,
|
||||
};
|
||||
|
||||
declare type ModerationBlockParams = {
|
||||
// Publisher, Moderator, or Commentron Admin
|
||||
mod_channel_id: string,
|
||||
mod_channel_name: string,
|
||||
// Offender being blocked
|
||||
blocked_channel_id: string,
|
||||
blocked_channel_name: string,
|
||||
// Creator that Moderator is delegated from. Used for delegated moderation
|
||||
creator_channel_id?: string,
|
||||
creator_channel_name?: string,
|
||||
// Blocks identity from comment universally, requires Admin rights on commentron instance
|
||||
block_all?: boolean,
|
||||
time_out?: number,
|
||||
// If true will delete all comments of the offender, requires Admin rights on commentron for universal delete
|
||||
delete_all?: boolean,
|
||||
// The usual signature stuff
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
};
|
||||
|
||||
declare type ModerationBlockResponse = {
|
||||
deleted_comment_ids: Array<string>,
|
||||
banned_channel_id: string,
|
||||
all_blocked: boolean,
|
||||
banned_from: string,
|
||||
};
|
||||
|
||||
declare type BlockedListArgs = {
|
||||
// Publisher, Moderator or Commentron Admin
|
||||
mod_channel_id: string,
|
||||
mod_channel_name: string,
|
||||
// Creator that Moderator is delegated from. Used for delegated moderation
|
||||
creator_channel_id?: string,
|
||||
creator_channel_name?: string,
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
};
|
||||
|
||||
declare type ModerationAddDelegateParams = {
|
||||
mod_channel_id: string,
|
||||
mod_channel_name: string,
|
||||
creator_channel_id: string,
|
||||
creator_channel_name: string,
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
};
|
||||
|
||||
declare type ModerationRemoveDelegateParams = {
|
||||
mod_channel_id: string,
|
||||
mod_channel_name: string,
|
||||
creator_channel_id: string,
|
||||
creator_channel_name: string,
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
};
|
||||
|
||||
declare type ModerationListDelegatesParams = {
|
||||
creator_channel_id: string,
|
||||
creator_channel_name: string,
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
};
|
||||
|
||||
declare type ModerationAmIParams = {
|
||||
channel_name: string,
|
||||
channel_id: string,
|
||||
signature: string,
|
||||
signing_ts: string
|
||||
};
|
||||
|
||||
declare type SettingsParams = {
|
||||
channel_name?: string,
|
||||
channel_id: string,
|
||||
signature?: string,
|
||||
signing_ts?: string,
|
||||
};
|
||||
|
||||
declare type SettingsResponse = {
|
||||
words?: string,
|
||||
comments_enabled: boolean,
|
||||
min_tip_amount_comment: number,
|
||||
min_tip_amount_super_chat: number,
|
||||
slow_mode_min_gap: number,
|
||||
curse_jar_amount: number,
|
||||
filters_enabled?: boolean,
|
||||
};
|
||||
|
||||
declare type UpdateSettingsParams = {
|
||||
channel_name: string,
|
||||
channel_id: string,
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
comments_enabled?: boolean,
|
||||
min_tip_amount_comment?: number,
|
||||
min_tip_amount_super_chat?: number,
|
||||
slow_mode_min_gap?: number,
|
||||
}
|
||||
|
||||
declare type BlockWordParams = {
|
||||
channel_name: string,
|
||||
channel_id: string,
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
words: string, // CSV list of containing words to block comment on content
|
||||
};
|
||||
|
|
78
flow-typed/File.js
vendored
Normal file
78
flow-typed/File.js
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
// @flow
|
||||
|
||||
declare type FileListItem = {
|
||||
metadata: StreamMetadata,
|
||||
added_on: number,
|
||||
blobs_completed: number,
|
||||
blobs_in_stream: number,
|
||||
blobs_remaining: number,
|
||||
channel_claim_id: string,
|
||||
channel_name: string,
|
||||
claim_id: string,
|
||||
claim_name: string,
|
||||
completed: false,
|
||||
content_fee?: { txid: string },
|
||||
purchase_receipt?: { txid: string, amount: string },
|
||||
download_directory: string,
|
||||
download_path: string,
|
||||
file_name: string,
|
||||
key: string,
|
||||
mime_type: string,
|
||||
nout: number,
|
||||
outpoint: string,
|
||||
points_paid: number,
|
||||
protobuf: string,
|
||||
reflector_progress: number,
|
||||
sd_hash: string,
|
||||
status: string,
|
||||
stopped: false,
|
||||
stream_hash: string,
|
||||
stream_name: string,
|
||||
streaming_url: string,
|
||||
suggested_file_name: string,
|
||||
total_bytes: number,
|
||||
total_bytes_lower_bound: number,
|
||||
is_fully_reflected: boolean,
|
||||
// TODO: sdk plans to change `tx`
|
||||
// It isn't currently used by the apps
|
||||
tx: {},
|
||||
txid: string,
|
||||
uploading_to_reflector: boolean,
|
||||
written_bytes: number,
|
||||
};
|
||||
|
||||
declare type FileState = {
|
||||
failedPurchaseUris: Array<string>,
|
||||
purchasedUris: Array<string>,
|
||||
};
|
||||
|
||||
declare type PurchaseUriCompleted = {
|
||||
type: ACTIONS.PURCHASE_URI_COMPLETED,
|
||||
data: {
|
||||
uri: string,
|
||||
streamingUrl: string,
|
||||
},
|
||||
};
|
||||
|
||||
declare type PurchaseUriFailed = {
|
||||
type: ACTIONS.PURCHASE_URI_FAILED,
|
||||
data: {
|
||||
uri: string,
|
||||
error: any,
|
||||
},
|
||||
};
|
||||
|
||||
declare type PurchaseUriStarted = {
|
||||
type: ACTIONS.PURCHASE_URI_STARTED,
|
||||
data: {
|
||||
uri: string,
|
||||
streamingUrl: string,
|
||||
},
|
||||
};
|
||||
|
||||
declare type DeletePurchasedUri = {
|
||||
type: ACTIONS.CLEAR_PURCHASED_URI_SUCCESS,
|
||||
data: {
|
||||
uri: string,
|
||||
},
|
||||
};
|
369
flow-typed/Lbry.js
vendored
Normal file
369
flow-typed/Lbry.js
vendored
Normal file
|
@ -0,0 +1,369 @@
|
|||
// @flow
|
||||
declare type StatusResponse = {
|
||||
blob_manager: {
|
||||
finished_blobs: number,
|
||||
},
|
||||
blockchain_headers: {
|
||||
download_progress: number,
|
||||
downloading_headers: boolean,
|
||||
},
|
||||
dht: {
|
||||
node_id: string,
|
||||
peers_in_routing_table: number,
|
||||
},
|
||||
hash_announcer: {
|
||||
announce_queue_size: number,
|
||||
},
|
||||
installation_id: string,
|
||||
is_running: boolean,
|
||||
skipped_components: Array<string>,
|
||||
startup_status: {
|
||||
blob_manager: boolean,
|
||||
blockchain_headers: boolean,
|
||||
database: boolean,
|
||||
dht: boolean,
|
||||
exchange_rate_manager: boolean,
|
||||
hash_announcer: boolean,
|
||||
peer_protocol_server: boolean,
|
||||
stream_manager: boolean,
|
||||
upnp: boolean,
|
||||
wallet: boolean,
|
||||
},
|
||||
stream_manager: {
|
||||
managed_files: number,
|
||||
},
|
||||
upnp: {
|
||||
aioupnp_version: string,
|
||||
dht_redirect_set: boolean,
|
||||
external_ip: string,
|
||||
gateway: string,
|
||||
peer_redirect_set: boolean,
|
||||
redirects: {},
|
||||
},
|
||||
wallet: ?{
|
||||
connected: string,
|
||||
best_blockhash: string,
|
||||
blocks: number,
|
||||
blocks_behind: number,
|
||||
is_encrypted: boolean,
|
||||
is_locked: boolean,
|
||||
headers_synchronization_progress: number,
|
||||
available_servers: number,
|
||||
},
|
||||
};
|
||||
|
||||
declare type VersionResponse = {
|
||||
build: string,
|
||||
lbrynet_version: string,
|
||||
os_release: string,
|
||||
os_system: string,
|
||||
platform: string,
|
||||
processor: string,
|
||||
python_version: string,
|
||||
};
|
||||
|
||||
declare type BalanceResponse = {
|
||||
available: string,
|
||||
reserved: string,
|
||||
reserved_subtotals: ?{
|
||||
claims: string,
|
||||
supports: string,
|
||||
tips: string,
|
||||
},
|
||||
total: string,
|
||||
};
|
||||
|
||||
declare type ResolveResponse = {
|
||||
// Keys are the url(s) passed to resolve
|
||||
[string]: { error?: {}, stream?: StreamClaim, channel?: ChannelClaim, collection?: CollectionClaim, claimsInChannel?: number },
|
||||
};
|
||||
|
||||
declare type GetResponse = FileListItem & { error?: string };
|
||||
|
||||
declare type GenericTxResponse = {
|
||||
height: number,
|
||||
hex: string,
|
||||
inputs: Array<{}>,
|
||||
outputs: Array<{}>,
|
||||
total_fee: string,
|
||||
total_input: string,
|
||||
total_output: string,
|
||||
txid: string,
|
||||
};
|
||||
|
||||
declare type PublishResponse = GenericTxResponse & {
|
||||
// Only first value in outputs is a claim
|
||||
// That's the only value we care about
|
||||
outputs: Array<Claim>,
|
||||
};
|
||||
|
||||
declare type ClaimSearchResponse = {
|
||||
items: Array<Claim>,
|
||||
page: number,
|
||||
page_size: number,
|
||||
total_items: number,
|
||||
total_pages: number,
|
||||
};
|
||||
|
||||
declare type ClaimListResponse = {
|
||||
items: Array<ChannelClaim | Claim>,
|
||||
page: number,
|
||||
page_size: number,
|
||||
total_items: number,
|
||||
total_pages: number,
|
||||
};
|
||||
|
||||
declare type ChannelCreateResponse = GenericTxResponse & {
|
||||
outputs: Array<ChannelClaim>,
|
||||
};
|
||||
|
||||
declare type ChannelUpdateResponse = GenericTxResponse & {
|
||||
outputs: Array<ChannelClaim>,
|
||||
};
|
||||
|
||||
declare type CommentCreateResponse = Comment;
|
||||
declare type CommentUpdateResponse = Comment;
|
||||
|
||||
declare type MyReactions = {
|
||||
// Keys are the commentId
|
||||
[string]: Array<string>,
|
||||
};
|
||||
|
||||
declare type OthersReactions = {
|
||||
// Keys are the commentId
|
||||
[string]: {
|
||||
// Keys are the reaction_type, e.g. 'like'
|
||||
[string]: number,
|
||||
},
|
||||
};
|
||||
|
||||
declare type CommentReactListResponse = {
|
||||
my_reactions: Array<MyReactions>,
|
||||
others_reactions: Array<OthersReactions>,
|
||||
};
|
||||
|
||||
declare type CommentHideResponse = {
|
||||
// keyed by the CommentIds entered
|
||||
[string]: { hidden: boolean },
|
||||
};
|
||||
|
||||
declare type CommentPinResponse = {
|
||||
// keyed by the CommentIds entered
|
||||
items: Comment,
|
||||
};
|
||||
|
||||
declare type CommentAbandonResponse = {
|
||||
// keyed by the CommentId given
|
||||
abandoned: boolean,
|
||||
};
|
||||
|
||||
declare type ChannelListResponse = {
|
||||
items: Array<ChannelClaim>,
|
||||
page: number,
|
||||
page_size: number,
|
||||
total_items: number,
|
||||
total_pages: number,
|
||||
};
|
||||
|
||||
declare type ChannelSignResponse = {
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
};
|
||||
|
||||
declare type CollectionCreateResponse = {
|
||||
outputs: Array<Claim>,
|
||||
page: number,
|
||||
page_size: number,
|
||||
total_items: number,
|
||||
total_pages: number,
|
||||
}
|
||||
|
||||
declare type CollectionListResponse = {
|
||||
items: Array<Claim>,
|
||||
page: number,
|
||||
page_size: number,
|
||||
total_items: number,
|
||||
total_pages: number,
|
||||
};
|
||||
|
||||
declare type CollectionResolveResponse = {
|
||||
items: Array<Claim>,
|
||||
total_items: number,
|
||||
};
|
||||
|
||||
declare type CollectionResolveOptions = {
|
||||
claim_id: string,
|
||||
};
|
||||
|
||||
declare type CollectionListOptions = {
|
||||
page: number,
|
||||
page_size: number,
|
||||
resolve?: boolean,
|
||||
};
|
||||
|
||||
declare type FileListResponse = {
|
||||
items: Array<FileListItem>,
|
||||
page: number,
|
||||
page_size: number,
|
||||
total_items: number,
|
||||
total_pages: number,
|
||||
};
|
||||
|
||||
declare type TxListResponse = {
|
||||
items: Array<Transaction>,
|
||||
page: number,
|
||||
page_size: number,
|
||||
total_items: number,
|
||||
total_pages: number,
|
||||
};
|
||||
|
||||
declare type SupportListResponse = {
|
||||
items: Array<Support>,
|
||||
page: number,
|
||||
page_size: number,
|
||||
total_items: number,
|
||||
total_pages: number,
|
||||
};
|
||||
|
||||
declare type BlobListResponse = { items: Array<string> };
|
||||
|
||||
declare type WalletListResponse = Array<{
|
||||
id: string,
|
||||
name: string,
|
||||
}>;
|
||||
|
||||
declare type WalletStatusResponse = {
|
||||
is_encrypted: boolean,
|
||||
is_locked: boolean,
|
||||
is_syncing: boolean,
|
||||
};
|
||||
|
||||
declare type SyncApplyResponse = {
|
||||
hash: string,
|
||||
data: string,
|
||||
};
|
||||
|
||||
declare type SupportAbandonResponse = GenericTxResponse;
|
||||
|
||||
declare type StreamListResponse = {
|
||||
items: Array<StreamClaim>,
|
||||
page: number,
|
||||
page_size: number,
|
||||
total_items: number,
|
||||
total_pages: number,
|
||||
};
|
||||
|
||||
declare type StreamRepostOptions = {
|
||||
name: string,
|
||||
bid: string,
|
||||
claim_id: string,
|
||||
channel_id?: string,
|
||||
};
|
||||
|
||||
declare type StreamRepostResponse = GenericTxResponse;
|
||||
|
||||
declare type PurchaseListResponse = {
|
||||
items: Array<PurchaseReceipt & { claim: StreamClaim }>,
|
||||
page: number,
|
||||
page_size: number,
|
||||
total_items: number,
|
||||
total_pages: number,
|
||||
};
|
||||
|
||||
declare type PurchaseListOptions = {
|
||||
page: number,
|
||||
page_size: number,
|
||||
resolve: boolean,
|
||||
claim_id?: string,
|
||||
channel_id?: string,
|
||||
};
|
||||
|
||||
//
|
||||
// Types used in the generic Lbry object that is exported
|
||||
//
|
||||
declare type LbryTypes = {
|
||||
isConnected: boolean,
|
||||
connectPromise: any, // null |
|
||||
connect: () => any, // void | Promise<any> ?
|
||||
daemonConnectionString: string,
|
||||
alternateConnectionString: string,
|
||||
methodsUsingAlternateConnectionString: Array<string>,
|
||||
apiRequestHeaders: { [key: string]: string },
|
||||
setDaemonConnectionString: string => void,
|
||||
setApiHeader: (string, string) => void,
|
||||
unsetApiHeader: string => void,
|
||||
overrides: { [string]: ?Function },
|
||||
setOverride: (string, Function) => void,
|
||||
// getMediaType: (?string, ?string) => string,
|
||||
|
||||
// Lbry Methods
|
||||
stop: () => Promise<string>,
|
||||
status: () => Promise<StatusResponse>,
|
||||
version: () => Promise<VersionResponse>,
|
||||
resolve: (params: {}) => Promise<ResolveResponse>,
|
||||
get: (params: {}) => Promise<GetResponse>,
|
||||
publish: (params: {}) => Promise<PublishResponse>,
|
||||
|
||||
claim_search: (params: {}) => Promise<ClaimSearchResponse>,
|
||||
claim_list: (params: {}) => Promise<ClaimListResponse>,
|
||||
channel_create: (params: {}) => Promise<ChannelCreateResponse>,
|
||||
channel_update: (params: {}) => Promise<ChannelUpdateResponse>,
|
||||
channel_import: (params: {}) => Promise<string>,
|
||||
channel_list: (params: {}) => Promise<ChannelListResponse>,
|
||||
channel_sign: (params: {}) => Promise<ChannelSignResponse>,
|
||||
stream_abandon: (params: {}) => Promise<GenericTxResponse>,
|
||||
stream_list: (params: {}) => Promise<StreamListResponse>,
|
||||
channel_abandon: (params: {}) => Promise<GenericTxResponse>,
|
||||
support_create: (params: {}) => Promise<GenericTxResponse>,
|
||||
support_list: (params: {}) => Promise<SupportListResponse>,
|
||||
support_abandon: (params: {}) => Promise<SupportAbandonResponse>,
|
||||
stream_repost: (params: StreamRepostOptions) => Promise<StreamRepostResponse>,
|
||||
purchase_list: (params: PurchaseListOptions) => Promise<PurchaseListResponse>,
|
||||
collection_resolve: (params: CollectionResolveOptions) => Promise<CollectionResolveResponse>,
|
||||
collection_list: (params: CollectionListOptions) => Promise<CollectionListResponse>,
|
||||
collection_create: (params: {}) => Promise<CollectionCreateResponse>,
|
||||
collection_update: (params: {}) => Promise<CollectionCreateResponse>,
|
||||
|
||||
// File fetching and manipulation
|
||||
file_list: (params: {}) => Promise<FileListResponse>,
|
||||
file_delete: (params: {}) => Promise<boolean>,
|
||||
blob_delete: (params: {}) => Promise<string>,
|
||||
blob_list: (params: {}) => Promise<BlobListResponse>,
|
||||
file_set_status: (params: {}) => Promise<any>,
|
||||
file_reflect: (params: {}) => Promise<any>,
|
||||
|
||||
// Preferences
|
||||
preference_get: (params?: {}) => Promise<any>,
|
||||
preference_set: (params: {}) => Promise<any>,
|
||||
|
||||
// Commenting
|
||||
comment_update: (params: {}) => Promise<CommentUpdateResponse>,
|
||||
comment_hide: (params: {}) => Promise<CommentHideResponse>,
|
||||
comment_abandon: (params: {}) => Promise<CommentAbandonResponse>,
|
||||
comment_list: (params: {}) => Promise<any>,
|
||||
comment_create: (params: {}) => Promise<any>,
|
||||
|
||||
// Wallet utilities
|
||||
wallet_balance: (params: {}) => Promise<BalanceResponse>,
|
||||
wallet_decrypt: (prams: {}) => Promise<boolean>,
|
||||
wallet_encrypt: (params: {}) => Promise<boolean>,
|
||||
wallet_unlock: (params: {}) => Promise<boolean>,
|
||||
wallet_list: (params: {}) => Promise<WalletListResponse>,
|
||||
wallet_send: (params: {}) => Promise<GenericTxResponse>,
|
||||
wallet_status: (params?: {}) => Promise<WalletStatusResponse>,
|
||||
address_is_mine: (params: {}) => Promise<boolean>,
|
||||
address_unused: (params: {}) => Promise<string>, // New address
|
||||
address_list: (params: {}) => Promise<string>,
|
||||
transaction_list: (params: {}) => Promise<TxListResponse>,
|
||||
txo_list: (params: {}) => Promise<any>,
|
||||
account_set: (params: {}) => Promise<any>,
|
||||
account_list: (params?: {}) => Promise<any>,
|
||||
|
||||
// Sync
|
||||
sync_hash: (params?: {}) => Promise<string>,
|
||||
sync_apply: (params: {}) => Promise<SyncApplyResponse>,
|
||||
// syncGet
|
||||
|
||||
// The app shouldn't need to do this
|
||||
utxo_release: () => Promise<any>,
|
||||
};
|
99
flow-typed/LbryFirst.js
vendored
Normal file
99
flow-typed/LbryFirst.js
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
// @flow
|
||||
declare type LbryFirstStatusResponse = {
|
||||
Version: string,
|
||||
Message: string,
|
||||
Running: boolean,
|
||||
Commit: string,
|
||||
};
|
||||
|
||||
declare type LbryFirstVersionResponse = {
|
||||
build: string,
|
||||
lbrynet_version: string,
|
||||
os_release: string,
|
||||
os_system: string,
|
||||
platform: string,
|
||||
processor: string,
|
||||
python_version: string,
|
||||
};
|
||||
/* SAMPLE UPLOAD RESPONSE (FULL)
|
||||
"Video": {
|
||||
"etag": "\"Dn5xIderbhAnUk5TAW0qkFFir0M/xlGLrlTox7VFTRcR8F77RbKtaU4\"",
|
||||
"id": "8InjtdvVmwE",
|
||||
"kind": "youtube#video",
|
||||
"snippet": {
|
||||
"categoryId": "22",
|
||||
"channelId": "UCXiVsGTU88fJjheB2rqF0rA",
|
||||
"channelTitle": "Mark Beamer",
|
||||
"liveBroadcastContent": "none",
|
||||
"localized": {
|
||||
"title": "my title"
|
||||
},
|
||||
"publishedAt": "2020-05-05T04:17:53.000Z",
|
||||
"thumbnails": {
|
||||
"default": {
|
||||
"height": 90,
|
||||
"url": "https://i9.ytimg.com/vi/8InjtdvVmwE/default.jpg?sqp=CMTQw_UF&rs=AOn4CLB6dlhZMSMrazDlWRsitPgCsn8fVw",
|
||||
"width": 120
|
||||
},
|
||||
"high": {
|
||||
"height": 360,
|
||||
"url": "https://i9.ytimg.com/vi/8InjtdvVmwE/hqdefault.jpg?sqp=CMTQw_UF&rs=AOn4CLB-Je_7l6qvASRAR_bSGWZHaXaJWQ",
|
||||
"width": 480
|
||||
},
|
||||
"medium": {
|
||||
"height": 180,
|
||||
"url": "https://i9.ytimg.com/vi/8InjtdvVmwE/mqdefault.jpg?sqp=CMTQw_UF&rs=AOn4CLCvSnDLqVznRNMKuvJ_0misY_chPQ",
|
||||
"width": 320
|
||||
}
|
||||
},
|
||||
"title": "my title"
|
||||
},
|
||||
"status": {
|
||||
"embeddable": true,
|
||||
"license": "youtube",
|
||||
"privacyStatus": "private",
|
||||
"publicStatsViewable": true,
|
||||
"uploadStatus": "uploaded"
|
||||
}
|
||||
}
|
||||
*/
|
||||
declare type UploadResponse = {
|
||||
Video: {
|
||||
id: string,
|
||||
snippet: {
|
||||
channelId: string,
|
||||
},
|
||||
status: {
|
||||
uploadStatus: string,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
declare type HasYTAuthResponse = {
|
||||
HashAuth: boolean,
|
||||
};
|
||||
|
||||
declare type YTSignupResponse = {};
|
||||
|
||||
//
|
||||
// Types used in the generic LbryFirst object that is exported
|
||||
//
|
||||
declare type LbryFirstTypes = {
|
||||
isConnected: boolean,
|
||||
connectPromise: ?Promise<any>,
|
||||
connect: () => void,
|
||||
lbryFirstConnectionString: string,
|
||||
apiRequestHeaders: { [key: string]: string },
|
||||
setApiHeader: (string, string) => void,
|
||||
unsetApiHeader: string => void,
|
||||
overrides: { [string]: ?Function },
|
||||
setOverride: (string, Function) => void,
|
||||
|
||||
// LbryFirst Methods
|
||||
stop: () => Promise<string>,
|
||||
status: () => Promise<StatusResponse>,
|
||||
version: () => Promise<VersionResponse>,
|
||||
upload: any => Promise<?UploadResponse>,
|
||||
hasYTAuth: string => Promise<HasYTAuthResponse>,
|
||||
ytSignup: () => Promise<YTSignupResponse>,
|
||||
};
|
136
flow-typed/Notification.js
vendored
Normal file
136
flow-typed/Notification.js
vendored
Normal file
|
@ -0,0 +1,136 @@
|
|||
// @flow
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
|
||||
/*
|
||||
Toasts:
|
||||
- First-in, first-out queue
|
||||
- Simple messages that are shown in response to user interactions
|
||||
- Never saved
|
||||
- If they are the result of errors, use the isError flag when creating
|
||||
- For errors that should interrupt user behavior, use Error
|
||||
*/
|
||||
declare type ToastParams = {
|
||||
message: string,
|
||||
title?: string,
|
||||
linkText?: string,
|
||||
linkTarget?: string,
|
||||
isError?: boolean,
|
||||
};
|
||||
|
||||
declare type Toast = {
|
||||
id: string,
|
||||
params: ToastParams,
|
||||
};
|
||||
|
||||
declare type DoToast = {
|
||||
type: ACTIONS.CREATE_TOAST,
|
||||
data: Toast,
|
||||
};
|
||||
|
||||
/*
|
||||
Notifications:
|
||||
- List of notifications based on user interactions/app notifications
|
||||
- Always saved, but can be manually deleted
|
||||
- Can happen in the background, or because of user interaction (ex: publish confirmed)
|
||||
*/
|
||||
declare type Notification = {
|
||||
id: string, // Unique id
|
||||
dateCreated: number,
|
||||
isRead: boolean, // Used to display "new" notifications that a user hasn't seen yet
|
||||
source?: string, // The type/area an notification is from. Used for sorting (ex: publishes, transactions)
|
||||
// We may want to use priority/isDismissed in the future to specify how urgent a notification is
|
||||
// and if the user should see it immediately
|
||||
// isDissmied: boolean,
|
||||
// priority?: number
|
||||
};
|
||||
|
||||
declare type DoNotification = {
|
||||
type: ACTIONS.CREATE_NOTIFICATION,
|
||||
data: Notification,
|
||||
};
|
||||
|
||||
declare type DoEditNotification = {
|
||||
type: ACTIONS.EDIT_NOTIFICATION,
|
||||
data: {
|
||||
notification: Notification,
|
||||
},
|
||||
};
|
||||
|
||||
declare type DoDeleteNotification = {
|
||||
type: ACTIONS.DELETE_NOTIFICATION,
|
||||
data: {
|
||||
id: string, // The id to delete
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
Errors:
|
||||
- First-in, first-out queue
|
||||
- Errors that should interupt user behavior
|
||||
- For errors that can be shown without interrupting a user, use Toast with the isError flag
|
||||
*/
|
||||
declare type ErrorNotification = {
|
||||
title: string,
|
||||
text: string,
|
||||
};
|
||||
|
||||
declare type DoError = {
|
||||
type: ACTIONS.CREATE_ERROR,
|
||||
data: ErrorNotification,
|
||||
};
|
||||
|
||||
declare type DoDismissError = {
|
||||
type: ACTIONS.DISMISS_ERROR,
|
||||
};
|
||||
|
||||
/*
|
||||
NotificationState
|
||||
*/
|
||||
declare type NotificationState = {
|
||||
notifications: Array<Notification>,
|
||||
errors: Array<ErrorNotification>,
|
||||
toasts: Array<Toast>,
|
||||
};
|
||||
|
||||
declare type WebNotification = {
|
||||
active_at: string,
|
||||
created_at: string,
|
||||
id: number,
|
||||
is_app_readable: boolean,
|
||||
is_device_notified: boolean,
|
||||
is_emailed: boolean,
|
||||
is_read: boolean,
|
||||
is_seen: boolean,
|
||||
notification_parameters: {
|
||||
device: {
|
||||
analytics_label: string,
|
||||
image_url: string,
|
||||
is_data_only: boolean,
|
||||
name: string,
|
||||
placeholders: ?string,
|
||||
target: string,
|
||||
text: string,
|
||||
title: string,
|
||||
type: string,
|
||||
},
|
||||
dynamic: {
|
||||
comment_author: string,
|
||||
reply_author: string,
|
||||
hash: string,
|
||||
claim_title: string,
|
||||
comment?: string,
|
||||
channel_url: string,
|
||||
},
|
||||
email: {},
|
||||
},
|
||||
notification_rule: string,
|
||||
type: string,
|
||||
updated_at: string,
|
||||
user_id: number,
|
||||
group_count?: number,
|
||||
};
|
||||
|
||||
declare type NotificationCategory = {
|
||||
name: string,
|
||||
types: ?Array<string>,
|
||||
};
|
|
@ -11,6 +11,7 @@ declare type UpdatePublishFormData = {
|
|||
thumbnail_url?: string,
|
||||
uploadThumbnailStatus?: string,
|
||||
thumbnailPath?: string,
|
||||
thumbnailError?: boolean,
|
||||
description?: string,
|
||||
language?: string,
|
||||
channel?: string,
|
||||
|
@ -24,7 +25,7 @@ declare type UpdatePublishFormData = {
|
|||
licenseType?: string,
|
||||
uri?: string,
|
||||
nsfw: boolean,
|
||||
isMarkdownPost: boolean,
|
||||
isMarkdownPost?: boolean,
|
||||
};
|
||||
|
||||
declare type PublishParams = {
|
6
flow-typed/Redux.js
vendored
Normal file
6
flow-typed/Redux.js
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
// @flow
|
||||
/* eslint-disable no-use-before-define */
|
||||
declare type GetState = () => any;
|
||||
declare type ThunkAction = (dispatch: Dispatch, getState: GetState) => any;
|
||||
declare type Dispatch = (action: {} | Promise<*> | Array<{}> | ThunkAction) => any; // Need to refer to ThunkAction
|
||||
/* eslint-enable */
|
5
flow-typed/Reflector.js
vendored
Normal file
5
flow-typed/Reflector.js
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
declare type ReflectingUpdate = {
|
||||
fileListItem: FileListItem,
|
||||
progress: number | boolean,
|
||||
stalled: boolean,
|
||||
};
|
13
flow-typed/Settings.js
vendored
Normal file
13
flow-typed/Settings.js
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
declare type CommentServerDetails = {
|
||||
name: string,
|
||||
url: string,
|
||||
}
|
||||
|
||||
declare type WalletServerDetails = {
|
||||
|
||||
};
|
||||
|
||||
declare type DiskSpace = {
|
||||
total: number,
|
||||
free: number,
|
||||
};
|
21
flow-typed/Tags.js
vendored
Normal file
21
flow-typed/Tags.js
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
declare type TagState = {
|
||||
followedTags: FollowedTags,
|
||||
knownTags: KnownTags,
|
||||
};
|
||||
|
||||
declare type Tag = {
|
||||
name: string,
|
||||
};
|
||||
|
||||
declare type KnownTags = {
|
||||
[string]: Tag,
|
||||
};
|
||||
|
||||
declare type FollowedTags = Array<string>;
|
||||
|
||||
declare type TagAction = {
|
||||
type: string,
|
||||
data: {
|
||||
name: string,
|
||||
},
|
||||
};
|
28
flow-typed/Transaction.js
vendored
Normal file
28
flow-typed/Transaction.js
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
// @flow
|
||||
declare type Transaction = {
|
||||
amount: number,
|
||||
claim_id: string,
|
||||
claim_name: string,
|
||||
fee: number,
|
||||
nout: number,
|
||||
txid: string,
|
||||
type: string,
|
||||
date: Date,
|
||||
};
|
||||
|
||||
declare type Support = {
|
||||
address: string,
|
||||
amount: string,
|
||||
claim_id: string,
|
||||
confirmations: number,
|
||||
height: string,
|
||||
is_change: string,
|
||||
is_mine: string,
|
||||
name: string,
|
||||
normalized_name: string,
|
||||
nout: string,
|
||||
permanent_url: string,
|
||||
timestamp: number,
|
||||
txid: string,
|
||||
type: string,
|
||||
};
|
27
flow-typed/Txo.js
vendored
Normal file
27
flow-typed/Txo.js
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
declare type Txo = {
|
||||
amount: number,
|
||||
claim_id: string,
|
||||
normalized_name: string,
|
||||
nout: number,
|
||||
txid: string,
|
||||
type: string,
|
||||
value_type: string,
|
||||
timestamp: number,
|
||||
is_my_output: boolean,
|
||||
is_my_input: boolean,
|
||||
is_spent: boolean,
|
||||
signing_channel?: {
|
||||
channel_id: string,
|
||||
},
|
||||
};
|
||||
|
||||
declare type TxoListParams = {
|
||||
page: number,
|
||||
page_size: number,
|
||||
type: string,
|
||||
is_my_input?: boolean,
|
||||
is_my_output?: boolean,
|
||||
is_not_my_input?: boolean,
|
||||
is_not_my_output?: boolean,
|
||||
is_spent?: boolean,
|
||||
};
|
16
flow-typed/comments.js
vendored
16
flow-typed/comments.js
vendored
|
@ -1,16 +0,0 @@
|
|||
// @flow
|
||||
declare type CommentListParams = {
|
||||
page: number,
|
||||
page_size: number,
|
||||
claim_id: string,
|
||||
};
|
||||
|
||||
declare type CommentAbandonParams = {
|
||||
comment_id: string,
|
||||
creator_channel_id?: string,
|
||||
creator_channel_name?: string,
|
||||
channel_id?: string,
|
||||
hexdata?: string,
|
||||
};
|
||||
|
||||
declare type ModerationBlockParams = {};
|
1
flow-typed/content.js
vendored
1
flow-typed/content.js
vendored
|
@ -2,6 +2,7 @@
|
|||
|
||||
declare type PlayingUri = {
|
||||
uri: string,
|
||||
primaryUri: string,
|
||||
pathname: string,
|
||||
commentId?: string,
|
||||
source?: string,
|
||||
|
|
10
flow-typed/file-data.js
vendored
Normal file
10
flow-typed/file-data.js
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
// @flow
|
||||
|
||||
declare type FileData = {
|
||||
file?: Blob,
|
||||
path: string,
|
||||
duration?: number,
|
||||
size?: number,
|
||||
mimeType: string,
|
||||
error?: string,
|
||||
}
|
9
flow-typed/file-with-path.js
vendored
Normal file
9
flow-typed/file-with-path.js
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
// @flow
|
||||
|
||||
declare type FileWithPath = {
|
||||
file: File,
|
||||
// The full path will only be available in
|
||||
// the application. For browser, the name
|
||||
// of the file will be used.
|
||||
path: string,
|
||||
}
|
9
flow-typed/homepage.js
vendored
9
flow-typed/homepage.js
vendored
|
@ -4,12 +4,12 @@ declare type HomepageObject = {
|
|||
options: any,
|
||||
route: string,
|
||||
title: string,
|
||||
}
|
||||
};
|
||||
|
||||
declare type HomepageData = {
|
||||
[string]: HomepageObject,
|
||||
default: any => any,
|
||||
}
|
||||
};
|
||||
|
||||
declare type RowDataItem = {
|
||||
title: any,
|
||||
|
@ -17,9 +17,12 @@ declare type RowDataItem = {
|
|||
help?: any,
|
||||
icon?: string,
|
||||
extra?: any,
|
||||
pinnedUrls?: Array<string>,
|
||||
options?: {
|
||||
channelIds?: Array<string>,
|
||||
pageSize: number,
|
||||
limitClaimsPerChannel?: number,
|
||||
pageSize?: number,
|
||||
languages?: Array<string>,
|
||||
},
|
||||
route?: string,
|
||||
hideForUnauth?: boolean,
|
||||
|
|
2
flow-typed/i18n.js
vendored
Normal file
2
flow-typed/i18n.js
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
// @flow
|
||||
declare function __(a: string, b?: {}): string;
|
21
flow-typed/lbryURI.js
vendored
Normal file
21
flow-typed/lbryURI.js
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
// @flow
|
||||
declare type LbryUrlObj = {
|
||||
// Path and channel will always exist when calling parseURI
|
||||
// But they may not exist when code calls buildURI
|
||||
isChannel?: boolean,
|
||||
path?: string,
|
||||
streamName?: string,
|
||||
streamClaimId?: string,
|
||||
channelName?: string,
|
||||
channelClaimId?: string,
|
||||
primaryClaimSequence?: number,
|
||||
secondaryClaimSequence?: number,
|
||||
primaryBidPosition?: number,
|
||||
secondaryBidPosition?: number,
|
||||
startTime?: number,
|
||||
|
||||
// Below are considered deprecated and should not be used due to unreliableness with claim.canonical_url
|
||||
claimName?: string,
|
||||
claimId?: string,
|
||||
contentName?: string,
|
||||
};
|
41
flow-typed/livestream.js
vendored
Normal file
41
flow-typed/livestream.js
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
// @flow
|
||||
|
||||
declare type LivestreamReplayItem = {
|
||||
data: {
|
||||
claimId: string,
|
||||
deleted: boolean,
|
||||
deletedAt: ?string,
|
||||
ffprobe: any,
|
||||
fileDuration: number, // decimal? float? string?
|
||||
fileType: string,
|
||||
fileLocation: string,
|
||||
fileSize: number,
|
||||
key: string,
|
||||
published: boolean,
|
||||
publishedAt: ?string,
|
||||
service: string,
|
||||
thumbnails: Array<string>,
|
||||
uploadedAt: string, // Date?
|
||||
},
|
||||
id: string,
|
||||
}
|
||||
declare type LivestreamReplayData = Array<LivestreamReplayItem>;
|
||||
|
||||
declare type LivestreamState = {
|
||||
fetchingById: {},
|
||||
viewersById: {},
|
||||
fetchingActiveLivestreams: boolean,
|
||||
activeLivestreams: ?LivestreamInfo,
|
||||
activeLivestreamsLastFetchedDate: number,
|
||||
activeLivestreamsLastFetchedOptions: {},
|
||||
}
|
||||
|
||||
declare type LivestreamInfo = {
|
||||
[/* creatorId */ string]: {
|
||||
live: boolean,
|
||||
viewCount: number,
|
||||
creatorId: string,
|
||||
latestClaimId: string,
|
||||
latestClaimUri: string,
|
||||
}
|
||||
}
|
38
flow-typed/notification.js
vendored
38
flow-typed/notification.js
vendored
|
@ -1,38 +0,0 @@
|
|||
// @flow
|
||||
declare type WebNotification = {
|
||||
active_at: string,
|
||||
created_at: string,
|
||||
id: number,
|
||||
is_app_readable: boolean,
|
||||
is_device_notified: boolean,
|
||||
is_emailed: boolean,
|
||||
is_read: boolean,
|
||||
is_seen: boolean,
|
||||
notification_parameters: {
|
||||
device: {
|
||||
analytics_label: string,
|
||||
image_url: string,
|
||||
is_data_only: boolean,
|
||||
name: string,
|
||||
placeholders: ?string,
|
||||
target: string,
|
||||
text: string,
|
||||
title: string,
|
||||
type: string,
|
||||
},
|
||||
dynamic: {
|
||||
comment_author: string,
|
||||
reply_author: string,
|
||||
hash: string,
|
||||
claim_title: string,
|
||||
comment?: string,
|
||||
channel_url: string,
|
||||
},
|
||||
email: {},
|
||||
},
|
||||
notification_rule: string,
|
||||
type: string,
|
||||
updated_at: string,
|
||||
user_id: number,
|
||||
group_count?: number,
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue