Compare commits
638 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
457bd15e17 | ||
|
|
cc1b8ee499 | ||
|
|
4a9ed1348e | ||
|
|
5595420be6 | ||
|
|
191e9ceb6f | ||
|
|
1e26faa57c | ||
|
|
030256c9e1 | ||
|
|
77eff12d9b | ||
|
|
2967fce013 | ||
|
|
db1def623a | ||
|
|
140e324bf1 | ||
|
|
f0bf051259 | ||
|
|
2ec47d52cd | ||
|
|
50002cfbbd | ||
|
|
6ccd4b8b37 | ||
|
|
c0894afff9 | ||
|
|
09f244150c | ||
|
|
efec8b320c | ||
|
|
e6ea9f77e9 | ||
|
|
0813aa4ba3 | ||
|
|
ba575f6b8d | ||
|
|
ff9b2338e0 | ||
|
|
d2bb4b38e3 | ||
|
|
760c08dd0c | ||
|
|
50517eb462 | ||
|
|
e77425c21e | ||
|
|
f63abb053d | ||
|
|
7b5703aa04 | ||
|
|
d641066312 | ||
|
|
44ca8d47d8 | ||
|
|
d5f41bf4ad | ||
|
|
73e8926444 | ||
|
|
5ad694af65 | ||
|
|
d7f7acb219 | ||
|
|
b4be51333a | ||
|
|
ae94811a00 | ||
|
|
a484f2f2cc | ||
|
|
9cce4e734d | ||
|
|
3c63644213 | ||
|
|
ad25bc34de | ||
|
|
0241e15691 | ||
|
|
af9a6b8a84 | ||
|
|
329b188435 | ||
|
|
2e49bb73c5 | ||
|
|
5158020293 | ||
|
|
feaf80ad1e | ||
|
|
7fbd89159e | ||
|
|
716861da18 | ||
|
|
d0a34d423c | ||
|
|
adfba72f19 | ||
|
|
f00337c376 | ||
|
|
737a023b65 | ||
|
|
5551344355 | ||
|
|
07f64382fb | ||
|
|
1c7cde2a19 | ||
|
|
8510a7f3d8 | ||
|
|
db60b11a17 | ||
|
|
6a212b762a | ||
|
|
c8ec2922cf | ||
|
|
b629b7d333 | ||
|
|
514a8b62d6 | ||
|
|
cd11618a5d | ||
|
|
8be3cb157a | ||
|
|
4ca57cc025 | ||
|
|
397bcc94c5 | ||
|
|
8b28bccfd7 | ||
|
|
c6107057d9 | ||
|
|
ab2a9530e9 | ||
|
|
bfc771bd99 | ||
|
|
e75e588755 | ||
|
|
0266bb49ca | ||
|
|
9e693fd555 | ||
|
|
1f30b9ec84 | ||
|
|
50862e3c03 | ||
|
|
20e90bbc34 | ||
|
|
2e212e6d10 | ||
|
|
2039bfa081 | ||
|
|
7dc8a99247 | ||
|
|
1b25ea7f95 | ||
|
|
1869382166 | ||
|
|
d58cd639c7 | ||
|
|
6cd2d4cf83 | ||
|
|
b681f5abd9 | ||
|
|
5b2a0feccf | ||
|
|
cd58f6bc73 | ||
|
|
aeabf806ac | ||
|
|
af7ba31c2f | ||
|
|
5b962b1b9d | ||
|
|
219a7ba8c3 | ||
|
|
933babb4e6 | ||
|
|
023ba2e051 | ||
|
|
8d82a6a3e6 | ||
|
|
88a8fda566 | ||
|
|
1c833a8b1d | ||
|
|
7143d7532d | ||
|
|
1f10bdf593 | ||
|
|
3b543916ff | ||
|
|
c4da85340a | ||
|
|
ec59c7e0f9 | ||
|
|
2454cd9a39 | ||
|
|
c19e2bea29 | ||
|
|
2f2c1ad49b | ||
|
|
657aff2167 | ||
|
|
2450457fe5 | ||
|
|
ba9e42e6f0 | ||
|
|
f05d80523b | ||
|
|
d2779aba86 | ||
|
|
852912a42b | ||
|
|
995fe072bd | ||
|
|
45e0f87f9f | ||
|
|
79b02c7ae7 | ||
|
|
cfb902180d | ||
|
|
1753c05686 | ||
|
|
c76d2c9a95 | ||
|
|
00117bdfac | ||
|
|
40cddbf8ee | ||
|
|
9026044528 | ||
|
|
50f293d783 | ||
|
|
2b558c43bd | ||
|
|
22cc51734f | ||
|
|
cd5adc1b82 | ||
|
|
b7e83a0efe | ||
|
|
6159605afd | ||
|
|
ceae02426d | ||
|
|
51d2886f70 | ||
|
|
c2eb973a28 | ||
|
|
f8532d39eb | ||
|
|
c2be1ee6d4 | ||
|
|
1735cdb45d | ||
|
|
be6cd62fbe | ||
|
|
cfe91f6280 | ||
|
|
4e7bfa5ed3 | ||
|
|
6f03c68fdc | ||
|
|
62653705ff | ||
|
|
8cdbebd6de | ||
|
|
94af8ab301 | ||
|
|
be3a4a4e91 | ||
|
|
3791c5c78b | ||
|
|
6bd22896b9 | ||
|
|
ea4331e4b1 | ||
|
|
84fbc93c8a | ||
|
|
553581f67b | ||
|
|
afe16e6623 | ||
|
|
0942da0cd1 | ||
|
|
c2b3835618 | ||
|
|
4a96a52398 | ||
|
|
4e1eb82538 | ||
|
|
885fae175d | ||
|
|
1cd84d8a2c | ||
|
|
0c891e0a09 | ||
|
|
08c7754f29 | ||
|
|
5f21d3f96f | ||
|
|
158b76c17e | ||
|
|
3455a79298 | ||
|
|
dd08ff1507 | ||
|
|
1c17464c94 | ||
|
|
b5996a9783 | ||
|
|
edb108bbcf | ||
|
|
8896c5707a | ||
|
|
feda7fd1a0 | ||
|
|
46ffb330fc | ||
|
|
2f7a4bdb36 | ||
|
|
96dab6b6b2 | ||
|
|
3e9afe1dc8 | ||
|
|
2df2b4c53d | ||
|
|
968dd34c3d | ||
|
|
0cbe73c527 | ||
|
|
6d312e7ba7 | ||
|
|
09a33c4252 | ||
|
|
76d966c1f9 | ||
|
|
da364b49f0 | ||
|
|
f6f416b899 | ||
|
|
3582f45fd8 | ||
|
|
13cef5ff14 | ||
|
|
4049d2d1ab | ||
|
|
db7ac02c7d | ||
|
|
26f3560e97 | ||
|
|
1eaf4f44c2 | ||
|
|
0a0d4d3e0f | ||
|
|
7f22687c24 | ||
|
|
7404e0831b | ||
|
|
e3be54cbe7 | ||
|
|
b0a23a5c4e | ||
|
|
5bb5dae20e | ||
|
|
bb9de35722 | ||
|
|
4907be7738 | ||
|
|
23141aa624 | ||
|
|
17381e7deb | ||
|
|
4bd410f04e | ||
|
|
20a09d3d27 | ||
|
|
98b36380b5 | ||
|
|
7716827a98 | ||
|
|
070a51954a | ||
|
|
de66e21d14 | ||
|
|
932cf8ecf1 | ||
|
|
4a491f1ebf | ||
|
|
5ebdfd8466 | ||
|
|
16c720e500 | ||
|
|
d77f8abf42 | ||
|
|
03836b69f2 | ||
|
|
5837205a9a | ||
|
|
0f346c2096 | ||
|
|
30acfdd788 | ||
|
|
478edfee7c | ||
|
|
a685950a66 | ||
|
|
69d1d709f6 | ||
|
|
1fcfdcd13c | ||
|
|
34a21c6d8c | ||
|
|
e6ef27936e | ||
|
|
2b7f940669 | ||
|
|
bdcd613f02 | ||
|
|
7255300903 | ||
|
|
21b2ad71b9 | ||
|
|
1ff7e69556 | ||
|
|
f7a3f98ad3 | ||
|
|
4cdb874b4f | ||
|
|
5df0801c64 | ||
|
|
e286797ac5 | ||
|
|
e784dc017d | ||
|
|
251339f26b | ||
|
|
3e3b8eab6f | ||
|
|
a7d769dd6d | ||
|
|
ad37e9abe7 | ||
|
|
f99a3f5088 | ||
|
|
6f2a09695b | ||
|
|
9ae8769869 | ||
|
|
f58a16179a | ||
|
|
297c95ac6b | ||
|
|
ced3100b4e | ||
|
|
7358be6faa | ||
|
|
03e29dbb81 | ||
|
|
7cb2915fd7 | ||
|
|
5348496768 | ||
|
|
7526abc3e1 | ||
|
|
1163b6f0ce | ||
|
|
7c809419f8 | ||
|
|
0a42f130ac | ||
|
|
4de0ae51e8 | ||
|
|
f5a4ffabde | ||
|
|
115b1edf11 | ||
|
|
04942a3a5d | ||
|
|
aee0712ef1 | ||
|
|
63568aae9c | ||
|
|
bf90d2a8e6 | ||
|
|
d87cb77895 | ||
|
|
36c4ebda65 | ||
|
|
968df5a2e4 | ||
|
|
259f7a9439 | ||
|
|
4f8e1bc827 | ||
|
|
9e8a520d1e | ||
|
|
7335429541 | ||
|
|
5c227f445a | ||
|
|
dce90e86bf | ||
|
|
36d7dcce9b | ||
|
|
502bec55c4 | ||
|
|
21a61bb238 | ||
|
|
fb974de53b | ||
|
|
a5adf73b88 | ||
|
|
1f4c4c0901 | ||
|
|
338fbcea9c | ||
|
|
a20fa9871e | ||
|
|
25436d9620 | ||
|
|
8d3a633d85 | ||
|
|
f67568e3b6 | ||
|
|
d902cc5efe | ||
|
|
9e89eb521a | ||
|
|
f4c5f50f8c | ||
|
|
4301a6bfe3 | ||
|
|
2c5a78947a | ||
|
|
8f7eb82b6e | ||
|
|
d2e1373e2a | ||
|
|
d705610855 | ||
|
|
c40b6576d6 | ||
|
|
1c3e2fcdad | ||
|
|
7acc6c3329 | ||
|
|
1715ee327f | ||
|
|
0481943737 | ||
|
|
c53bc20294 | ||
|
|
a8fc22eae8 | ||
|
|
4ba82f6e00 | ||
|
|
8fd671d4d3 | ||
|
|
309b1b007e | ||
|
|
d0e7213cc4 | ||
|
|
a2e9688418 | ||
|
|
f42c23cd9a | ||
|
|
52f60d70e2 | ||
|
|
339d05e157 | ||
|
|
c0c3640638 | ||
|
|
a314139302 | ||
|
|
bfa0472f84 | ||
|
|
fa19e435cc | ||
|
|
eb4bf89194 | ||
|
|
da8a1376a7 | ||
|
|
267132cdde | ||
|
|
b8ebe5076b | ||
|
|
cb9877b3b4 | ||
|
|
c73b9ed5a6 | ||
|
|
1bd0b4349f | ||
|
|
d15785146f | ||
|
|
47d9d93818 | ||
|
|
601ff44145 | ||
|
|
cbd451949b | ||
|
|
a7dc207c5f | ||
|
|
c20b67d11f | ||
|
|
0b9def800b | ||
|
|
d8ae73e96a | ||
|
|
c99f7925eb | ||
|
|
3627661e1f | ||
|
|
f1c68a98cf | ||
|
|
92f10d51aa | ||
|
|
bdae68be35 | ||
|
|
2a4abf958d | ||
|
|
1362331a93 | ||
|
|
a70aa7723e | ||
|
|
a3f5200c9a | ||
|
|
1005783034 | ||
|
|
278e40207c | ||
|
|
509b627e88 | ||
|
|
ecd9f6eaff | ||
|
|
1d2b6b2010 | ||
|
|
6c4d5c0705 | ||
|
|
0533919bde | ||
|
|
e02ca1c822 | ||
|
|
039c1a178f | ||
|
|
6f682baa45 | ||
|
|
0241c0a036 | ||
|
|
4ebdcf1cc5 | ||
|
|
46c3187c89 | ||
|
|
c65e3c21e3 | ||
|
|
e35774138f | ||
|
|
a9b678f0ff | ||
|
|
32356d711d | ||
|
|
477ae3eb2c | ||
|
|
0b41118232 | ||
|
|
ea3f9f246e | ||
|
|
9dd954e7d8 | ||
|
|
41352a5116 | ||
|
|
1ac9989288 | ||
|
|
b441cc2123 | ||
|
|
5e2bc43722 | ||
|
|
da17dd8bae | ||
|
|
87098d1c3e | ||
|
|
2a1b60596b | ||
|
|
7bbbe0dcf3 | ||
|
|
25672a6496 | ||
|
|
796bf6ef45 | ||
|
|
6ceeaebd9d | ||
|
|
61b8427270 | ||
|
|
4450aaa3b3 | ||
|
|
b0e0c380dd | ||
|
|
8baf11a053 | ||
|
|
67f9697f3f | ||
|
|
a94d941125 | ||
|
|
2917de6776 | ||
|
|
272698f97b | ||
|
|
3fbb689e0a | ||
|
|
4817af5e4f | ||
|
|
aba08a515e | ||
|
|
83801db82e | ||
|
|
84e4adbc12 | ||
|
|
6a37753753 | ||
|
|
0898c7e28c | ||
|
|
412be37ae5 | ||
|
|
beec376e10 | ||
|
|
df30f00347 | ||
|
|
dcfdade927 | ||
|
|
741ddcd8aa | ||
|
|
433db26078 | ||
|
|
fc033cb69d | ||
|
|
bd8c67bc24 | ||
|
|
a80fbc1a04 | ||
|
|
e347504616 | ||
|
|
94cbf089db | ||
|
|
cb2fb6925b | ||
|
|
b3361a473c | ||
|
|
fcb6ed7676 | ||
|
|
91f4d7f669 | ||
|
|
2e2ff60c23 | ||
|
|
13727270d4 | ||
|
|
b27f56bc00 | ||
|
|
7ad7d793d0 | ||
|
|
491bef680e | ||
|
|
e581dc818f | ||
|
|
8d0b032eb6 | ||
|
|
9cb4fd6f79 | ||
|
|
87abcae249 | ||
|
|
fe608b579e | ||
|
|
f74e25a482 | ||
|
|
1db9d25f3b | ||
|
|
f25aeefe83 | ||
|
|
1abc1b9b28 | ||
|
|
d10c8041bf | ||
|
|
c14c795474 | ||
|
|
e5937431c3 | ||
|
|
b24a688e63 | ||
|
|
10fd22f49c | ||
|
|
f1dda95847 | ||
|
|
f3f6dd171b | ||
|
|
c802212a62 | ||
|
|
afb666797d | ||
|
|
85a591c984 | ||
|
|
3edaea8102 | ||
|
|
93c39c3ecc | ||
|
|
ab2f0ef395 | ||
|
|
005ca73cce | ||
|
|
8dd8897f1f | ||
|
|
95555ed3fd | ||
|
|
11b71f7366 | ||
|
|
4537c70105 | ||
|
|
42a0cff162 | ||
|
|
527e6d4c24 | ||
|
|
2c19da2117 | ||
|
|
7ee1cc911f | ||
|
|
9fc846bd7a | ||
|
|
5b628ccbf9 | ||
|
|
5471273673 | ||
|
|
58c0c6e152 | ||
|
|
36078acaee | ||
|
|
7d62c9f575 | ||
|
|
45a64fcb03 | ||
|
|
630b099fd6 | ||
|
|
c17e47ddd3 | ||
|
|
81bf54c42d | ||
|
|
5b693e81fd | ||
|
|
00115cd707 | ||
|
|
e992844fa2 | ||
|
|
b30acaac78 | ||
|
|
46ac654224 | ||
|
|
8578e96c3a | ||
|
|
b42bdc6e6f | ||
|
|
369364f574 | ||
|
|
a5baebab3f | ||
|
|
b34e6076e4 | ||
|
|
226c5d601c | ||
|
|
cc1a12e1a2 | ||
|
|
1d342b21fd | ||
|
|
5dc67a386c | ||
|
|
6d442b9e80 | ||
|
|
2f6ddeb5f1 | ||
|
|
3d01ffee1b | ||
|
|
9c51df9159 | ||
|
|
3a29fcc3d8 | ||
|
|
b18f2ae60d | ||
|
|
ab07478e25 | ||
|
|
d6aeec933a | ||
|
|
cd5207f816 | ||
|
|
381c11ed99 | ||
|
|
62d4b365c2 | ||
|
|
524df6389a | ||
|
|
24292e771b | ||
|
|
f35d34a807 | ||
|
|
468e33eff7 | ||
|
|
600f9e4b85 | ||
|
|
9cb3da4a7f | ||
|
|
a66c7c8063 | ||
|
|
0a84dbd3a5 | ||
|
|
2fa412e574 | ||
|
|
f240416886 | ||
|
|
2a025b7977 | ||
|
|
f44d2b67e5 | ||
|
|
6b15ebac99 | ||
|
|
ff41251f17 | ||
|
|
c7c1cb79a8 | ||
|
|
fc155ccdfa | ||
|
|
dfad1a5636 | ||
|
|
6790952f86 | ||
|
|
1a28f714a1 | ||
|
|
55a55fefba | ||
|
|
fe74f7caa3 | ||
|
|
108aac0e79 | ||
|
|
008c07acc3 | ||
|
|
831a3c1b5a | ||
|
|
dc7b63d735 | ||
|
|
9267f36165 | ||
|
|
ae6d63c3ab | ||
|
|
a3214f0fa7 | ||
|
|
d4bd5313fc | ||
|
|
c69fe53ea6 | ||
|
|
d7c496847f | ||
|
|
44516648a1 | ||
|
|
fbeabc830b | ||
|
|
f370746382 | ||
|
|
e82beb861a | ||
|
|
1791d31681 | ||
|
|
784ddea34a | ||
|
|
69c93a0563 | ||
|
|
4e4d50de82 | ||
|
|
25b9edabf8 | ||
|
|
6851470547 | ||
|
|
73c1fc17b3 | ||
|
|
cba5b05c0c | ||
|
|
3f1573f1b3 | ||
|
|
93ffc93943 | ||
|
|
4214af4d56 | ||
|
|
01405dd32e | ||
|
|
047432af03 | ||
|
|
a8bd5d0068 | ||
|
|
eeb6d20e96 | ||
|
|
8bb8511bf4 | ||
|
|
563610cbcd | ||
|
|
04190b27d8 | ||
|
|
1782376e3d | ||
|
|
ef1b96bbf1 | ||
|
|
7deea5d648 | ||
|
|
c6460b006f | ||
|
|
4352667b1c | ||
|
|
a84502dc92 | ||
|
|
d7c67fb481 | ||
|
|
adc9748d4d | ||
|
|
f310c53f88 | ||
|
|
f2c2fd0d29 | ||
|
|
1b0cd0f485 | ||
|
|
48f6f2f66c | ||
|
|
85b70f8ad7 | ||
|
|
3e32f28d2e | ||
|
|
9bd1b03504 | ||
|
|
cdccc43b31 | ||
|
|
21ce614bd9 | ||
|
|
7f56ec238f | ||
|
|
e1625437d4 | ||
|
|
5b9afebd4e | ||
|
|
93afc06717 | ||
|
|
cfbf1f8995 | ||
|
|
516e5077a9 | ||
|
|
0c2ceb134b | ||
|
|
02bcb0b213 | ||
|
|
35c6ed81b5 | ||
|
|
a229aee2cc | ||
|
|
f91c6d5f9d | ||
|
|
0e93fb6f57 | ||
|
|
1f491d2031 | ||
|
|
32dd7d43d7 | ||
|
|
284efe9902 | ||
|
|
4e795c8fb1 | ||
|
|
c83eb589ea | ||
|
|
7cd6b324b9 | ||
|
|
5891fccacb | ||
|
|
59233f3307 | ||
|
|
796466a72a | ||
|
|
3f35642010 | ||
|
|
5bbfcf742d | ||
|
|
aaf79fda0d | ||
|
|
8604788d27 | ||
|
|
519a822751 | ||
|
|
fef31c399b | ||
|
|
5802e05228 | ||
|
|
da21081a12 | ||
|
|
6d739de57c | ||
|
|
edcd328743 | ||
|
|
5c9e6cac0e | ||
|
|
7ab5e2cf52 | ||
|
|
42dcdb40cf | ||
|
|
896357a943 | ||
|
|
2d96c24b13 | ||
|
|
1753f58120 | ||
|
|
7244ca8f5e | ||
|
|
ec0c989066 | ||
|
|
c801b1fecd | ||
|
|
57b50106d1 | ||
|
|
871ba63f67 | ||
|
|
f0888faf78 | ||
|
|
23fbbebc9e | ||
|
|
9951a19478 | ||
|
|
dd4ab2f38a | ||
|
|
6bcdb3e272 | ||
|
|
227bec4d8e | ||
|
|
556b4f88d2 | ||
|
|
2d12f957bc | ||
|
|
c1efe02614 | ||
|
|
f0e1979aab | ||
|
|
989db6d6b6 | ||
|
|
781096c290 | ||
|
|
536c6e3e41 | ||
|
|
de376176db | ||
|
|
e63389cfa3 | ||
|
|
1c4ca8da26 | ||
|
|
dcbd7ba4cd | ||
|
|
9fc8d385ab | ||
|
|
07e878e065 | ||
|
|
a2af4dba52 | ||
|
|
2fbafb6b10 | ||
|
|
98eb72ef1f | ||
|
|
89d127c5c5 | ||
|
|
a784c8a850 | ||
|
|
a533aaf5cf | ||
|
|
434b5bdbad | ||
|
|
d1f1f9213e | ||
|
|
d498c107a8 | ||
|
|
f12b44762e | ||
|
|
fc4da038e9 | ||
|
|
d5999ad330 | ||
|
|
146ece3bff | ||
|
|
92095acf36 | ||
|
|
279c10d555 | ||
|
|
0ae3820681 | ||
|
|
283e4d053e | ||
|
|
6dbb2f9d10 | ||
|
|
c657bb763b | ||
|
|
259cdb1abe | ||
|
|
86e96e59af | ||
|
|
9ba30dbafa | ||
|
|
2907db705c | ||
|
|
a6a0f917e0 | ||
|
|
bcdba798d9 | ||
|
|
32884372fa | ||
|
|
9b2364cfb7 | ||
|
|
c1aebf45c8 | ||
|
|
6e0c6332cc | ||
|
|
47d0d340d4 | ||
|
|
118804e139 | ||
|
|
0bef50e259 | ||
|
|
bfb876af8b | ||
|
|
84d5d3124c | ||
|
|
825d997d6d | ||
|
|
8e9e5bfddb | ||
|
|
05765682a5 | ||
|
|
2b5d56942a | ||
|
|
f097ff60aa | ||
|
|
655691a28f | ||
|
|
7ddef8d519 | ||
|
|
2fb79f0066 | ||
|
|
655d87ce0f | ||
|
|
ed7c98afa8 | ||
|
|
41bf0c9697 | ||
|
|
5eb0132660 | ||
|
|
c43695e596 | ||
|
|
9aeda25136 | ||
|
|
90e671ebf8 | ||
|
|
3ecc180d06 | ||
|
|
7ac9ec37ef | ||
|
|
e176a9f241 | ||
|
|
91bd910c40 | ||
|
|
a6c77185de | ||
|
|
b871d721db | ||
|
|
85f9bb1d34 | ||
|
|
adb60c6357 | ||
|
|
4db6593681 | ||
|
|
d75a7ca897 |
62
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
name: Create artifacts
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# Initialization
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-node@v1
|
||||
- run: npm install
|
||||
- name: Copy configuration
|
||||
run: cp config.json.example config.json
|
||||
|
||||
# Create Chrome artifacts
|
||||
- name: Create Chrome artifacts
|
||||
run: npm run build:chrome
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: ChromeExtension
|
||||
path: dist
|
||||
- run: mkdir ./builds
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/ChromeExtension.zip ./dist
|
||||
|
||||
# Create Firefox artifacts
|
||||
- name: Create Firefox artifacts
|
||||
run: npm run build:firefox
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: FirefoxExtension
|
||||
path: dist
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/FirefoxExtension.zip ./dist
|
||||
|
||||
# Create Beta artifacts (Builds with the name changed to beta)
|
||||
- name: Create Chrome Beta artifacts
|
||||
run: npm run build:chrome -- --env.stream=beta
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: ChromeExtensionBeta
|
||||
path: dist
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/ChromeExtensionBeta.zip ./dist
|
||||
|
||||
- name: Create Firefox Beta artifacts
|
||||
run: npm run build:firefox -- --env.stream=beta
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: FirefoxExtensionBeta
|
||||
path: dist
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/FirefoxExtensionBeta.zip ./dist
|
||||
|
||||
78
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
name: Upload Release Build
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
name: Upload Release
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# Initialization
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-node@v1
|
||||
- run: npm install
|
||||
- name: Copy configuration
|
||||
run: cp config.json.example config.json
|
||||
|
||||
# Create Chrome artifacts
|
||||
- name: Create Chrome artifacts
|
||||
run: npm run build:chrome
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: ChromeExtension
|
||||
path: dist
|
||||
- run: mkdir ./builds
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/ChromeExtension.zip ./dist
|
||||
|
||||
# Create Firefox artifacts
|
||||
- name: Create Firefox artifacts
|
||||
run: npm run build:firefox
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: FirefoxExtension
|
||||
path: dist
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/FirefoxExtension.zip ./dist
|
||||
|
||||
# Create Beta artifacts (Builds with the name changed to beta)
|
||||
- name: Create Chrome Beta artifacts
|
||||
run: npm run build:chrome -- --env.stream=beta
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: ChromeExtensionBeta
|
||||
path: dist
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/ChromeExtensionBeta.zip ./dist
|
||||
|
||||
- name: Create Firefox Beta artifacts
|
||||
run: npm run build:firefox -- --env.stream=beta
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: FirefoxExtensionBeta
|
||||
path: dist
|
||||
- uses: montudor/action-zip@v0.1.0
|
||||
with:
|
||||
args: zip -qq -r ./builds/FirefoxExtensionBeta.zip ./dist
|
||||
|
||||
# Upload each release asset
|
||||
- name: Upload to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: builds/ChromeExtension.zip
|
||||
env:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload to release
|
||||
uses: Shopify/upload-to-release@master
|
||||
with:
|
||||
args: builds/FirefoxExtension.zip
|
||||
env:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
10
.gitignore
vendored
@@ -1,2 +1,8 @@
|
||||
config.js
|
||||
ignored
|
||||
config.json
|
||||
ignored
|
||||
.idea/
|
||||
node_modules
|
||||
web-ext-artifacts
|
||||
.vscode/
|
||||
dist/
|
||||
tmp/
|
||||
63
README.md
@@ -1,15 +1,38 @@
|
||||

|
||||
<br/><sub>Logo by [@munadikieh](https://github.com/munadikieh)</sub>
|
||||
<p align="center">
|
||||
<a href="https://sponsor.ajay.app"><img src="public/icons/LogoSponsorBlocker256px.png" alt="Logo"></img></a>
|
||||
|
||||
<br/>
|
||||
<sub>Logo by <a href="https://github.com/munadikieh">@munadikieh</a></sub>
|
||||
</p>
|
||||
|
||||
<h1 align="center">SponsorBlock</h1>
|
||||
|
||||
<p align="center">
|
||||
<b>Download:</b>
|
||||
<a href="https://chrome.google.com/webstore/detail/mnjggcdmjocbbbhaepdhchncahnbgone">Chrome/Chromium</a> |
|
||||
<a href="https://addons.mozilla.org/addon/sponsorblock/?src=external-github">Firefox</a> |
|
||||
<a href="https://sponsor.ajay.app">Website</a> |
|
||||
<a href="https://sponsor.ajay.app/stats">Stats</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<b>Unofficial Ports:</b>
|
||||
<a href="https://github.com/ajayyy/SponsorBlock/wiki/Unofficial-Ports#mpv-media-player">MPV</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://addons.mozilla.org/addon/sponsorblock/?src=external-github"><img src="https://img.shields.io/amo/users/sponsorblock?label=Firefox%20Users" alt="Badge"></img></a>
|
||||
<a href="https://chrome.google.com/webstore/detail/mnjggcdmjocbbbhaepdhchncahnbgone"><img src="https://img.shields.io/chrome-web-store/users/mnjggcdmjocbbbhaepdhchncahnbgone?label=Chome%20Users" alt="Badge"></img></a>
|
||||
<a href="https://sponsor.ajay.app/stats"><img src="https://img.shields.io/badge/dynamic/json?label=Sponsors%20Submitted&query=totalSubmissions&suffix=%20sponsors&url=http%3A%2F%2Fsponsor.ajay.app%2Fapi%2FgetTotalStats&color=darkred" alt="Badge"></img></a>
|
||||
<a href="https://sponsor.ajay.app/stats"><img src="https://img.shields.io/badge/dynamic/json?label=Contributing%20Users&query=userCount&url=http%3A%2F%2Fsponsor.ajay.app%2Fapi%2FgetTotalStats&color=darkblue" alt="Badge"></img></a>
|
||||
<a href="https://sponsor.ajay.app/stats"><img src="https://img.shields.io/badge/dynamic/json?label=Time%20Saved%20From%20Skips&query=daysSaved&url=http%3A%2F%2Fsponsor.ajay.app%2Fapi%2FgetDaysSavedFormatted&color=darkgreen&suffix=%20days" alt="Badge"></img></a>
|
||||
</p>
|
||||
|
||||
|
||||
# SponsorBlock
|
||||
|
||||
SponsorBlock is an extension that will skip over sponsored segments of YouTube videos. SponsorBlock is a crowdsourced browser extension that lets anyone submit the start and end times of sponsored segments of YouTube videos. Once one person submits this information, everyone else with this extension will skip right over the sponsored segment.
|
||||
|
||||
# Available for Chrome and Firefox
|
||||
|
||||
Chrome: https://chrome.google.com/webstore/detail/mnjggcdmjocbbbhaepdhchncahnbgone
|
||||
|
||||
Firefox: https://addons.mozilla.org/addon/sponsorblock/
|
||||
Also support Invidio.us.
|
||||
|
||||
# Server
|
||||
|
||||
@@ -17,25 +40,35 @@ The backend server code is available here: https://github.com/ajayyy/SponsorBloc
|
||||
|
||||
It is a simple Sqlite database that will hold all the timing data.
|
||||
|
||||
To make sure that this project doesn't die, I have made the database publicly downloadable at https://sponsor.ajay.app/database.db. So, you can download a backup or get archive.org to take a backup if you do desire.
|
||||
To make sure that this project doesn't die, I have made the database publicly downloadable at https://sponsor.ajay.app/database.db. You can download a backup or get archive.org to take a backup for you if you want.
|
||||
|
||||
Hopefully this project can be combined with projects like [this](https://github.com/Sponsoff/sponsorship_remover) and use this data to create a neural network to predict when sponsored segments happen. That project is sadly abandoned now, so I have decided to attempt to revive this idea.
|
||||
The dataset and API are now being used in some [ports](https://github.com/ajayyy/SponsorBlock/wiki/Unofficial-Ports) as well as a [neural network](https://github.com/andrewzlee/NeuralBlock).
|
||||
|
||||
A [previous project](https://github.com/Sponsoff/sponsorship_remover) attempted to create a neural network to predict when sponsored segments happen. That project is sadly abandoned now, so I have decided to attempt to revive this idea starting from a crowd-sourced system instead.
|
||||
|
||||
# API
|
||||
|
||||
You can read the API docs [here](https://github.com/ajayyy/SponsorBlockServer#api-docs).
|
||||
|
||||
# Previous extension
|
||||
# Building
|
||||
|
||||
This project is partially based off of [this experimental extension](https://github.com/OfficialNoob/YTSponsorSkip), which has the basic video skipping functionality.
|
||||
There are also other build scripts available. Install `npm`, then run `npm install` in the repository to install dependencies.
|
||||
|
||||
# Build Yourself
|
||||
Run `npm run build` to generate a Chrome extension.
|
||||
|
||||
You can load this project as an unpacked extension. Make sure to rename the `config.js.example` file to `config.js` before installing.
|
||||
Use `npm run build:firefox` to generate a Firefox extension.
|
||||
|
||||
The result is in `dist`. This can be loaded as an unpacked extension
|
||||
|
||||
## Developing with a clean profile
|
||||
|
||||
Run `npm run dev` to run the extension using a clean browser profile with hot reloading. Use `npm run dev:firefox` for Firefox. This uses [`web-ext run`](https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#commands).
|
||||
|
||||
# Credit
|
||||
|
||||
The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) is used to grab the time the video was published.
|
||||
The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) previously was used.
|
||||
|
||||
Originally forked from [YTSponsorSkip](https://github.com/OfficialNoob/YTSponsorSkip), but zero code remains.
|
||||
|
||||
Some icons made by <a href="https://www.flaticon.com/authors/gregor-cresnar" title="Gregor Cresnar">Gregor Cresnar</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> and are licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a>
|
||||
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock for YouTube - Skip Sponsorships",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Skip over sponsorship on YouTube videos. Report sponsors on videos you watch to save the time of others.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Server said this request was invalid"
|
||||
},
|
||||
"429": {
|
||||
"message": "You have submitted too many sponsor times for this one video, are you sure there are this many?"
|
||||
},
|
||||
"409": {
|
||||
"message": "This has already been submitted before"
|
||||
},
|
||||
"502": {
|
||||
"message": "It seems the server is down. Contact the dev to inform them."
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Channel Whitelisted!"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "Sponsor"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "Sponsors"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "sponsor segment"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "sponsor segments"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Sponsor Skipped"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Report"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Report this sponsor submission as incorrect."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Dismiss"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Loading..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minutes"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Seconds"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Never Show"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Hit unskip to get to where you came from."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Unskip"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Reskip"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Paused"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "\n\nTo edit or delete individual values, click the info button or open the extension popup by clicking the extension icon in the top right corner."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Are you sure you want to clear this?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "There was an error submitting your sponsor times, please try again later."
|
||||
},
|
||||
|
||||
"sponsorFound": {
|
||||
"message": "This video's sponsors are in the database!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "No sponsors found"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Sponsorship Starts Now"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Sponsorship Ends Now"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "This probably isn't a YouTube tab, or you clicked too early. \n If you know this is a YouTube tab,\n close this popup and open it again."
|
||||
},
|
||||
"success": {
|
||||
"message": "Success!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Voted!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "You have already voted this way before."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "It seems the sever is down. Contact the dev immediately."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "A connection error has occured. Error code: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Do you want to submit the sponsor times for video id"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "You seem to have left some sponsor times unsubmitted. Go back to that page to submit them (they are not deleted)."
|
||||
}
|
||||
}
|
||||
221
background.js
@@ -1,221 +0,0 @@
|
||||
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
|
||||
chrome.tabs.sendMessage(tabId, {
|
||||
message: 'update',
|
||||
});
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||
switch(request.message) {
|
||||
case "submitTimes":
|
||||
submitTimes(request.videoID, callback);
|
||||
|
||||
//this allows the callback to be called later by the submitTimes function
|
||||
return true;
|
||||
case "addSponsorTime":
|
||||
addSponsorTime(request.time, request.videoID, callback);
|
||||
|
||||
//this allows the callback to be called later
|
||||
return true;
|
||||
case "getSponsorTimes":
|
||||
getSponsorTimes(request.videoID, function(sponsorTimes) {
|
||||
callback({
|
||||
sponsorTimes: sponsorTimes
|
||||
})
|
||||
});
|
||||
|
||||
//this allows the callback to be called later
|
||||
return true;
|
||||
case "submitVote":
|
||||
submitVote(request.type, request.UUID, callback);
|
||||
|
||||
//this allows the callback to be called later
|
||||
return true;
|
||||
case "alertPrevious":
|
||||
chrome.notifications.create("stillThere" + Math.random(), {
|
||||
type: "basic",
|
||||
title: "Do you want to submit the sponsor times for video id " + request.previousVideoID + "?",
|
||||
message: "You seem to have left some sponsor times unsubmitted. Go back to that page to submit them (they are not deleted).",
|
||||
iconUrl: "./icons/LogoSponsorBlocker256px.png"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//add help page on install
|
||||
chrome.runtime.onInstalled.addListener(function (object) {
|
||||
// TODO (shownInstallPage): remove shownInstallPage logic after sufficient amount of time,
|
||||
// so that people have time to upgrade and move to shownInstallPage-free code.
|
||||
chrome.storage.sync.get(["userID", "shownInstallPage"], function(result) {
|
||||
const userID = result.userID;
|
||||
// TODO (shownInstallPage): delete row below
|
||||
const shownInstallPage = result.shownInstallPage;
|
||||
|
||||
// If there is no userID, then it is the first install.
|
||||
if (!userID){
|
||||
// Show install page, if there is no user id
|
||||
// and there is no shownInstallPage.
|
||||
// TODO (shownInstallPage): remove this if statement, but leave contents
|
||||
if (!shownInstallPage){
|
||||
//open up the install page
|
||||
|
||||
chrome.tabs.create({url: chrome.extension.getURL("/help/"+chrome.i18n.getMessage("helpPage"))});
|
||||
}
|
||||
|
||||
// TODO (shownInstallPage): delete if statement and contents
|
||||
// If shownInstallPage is set, remove it.
|
||||
if (!!shownInstallPage){
|
||||
chrome.storage.sync.remove("shownInstallPage");
|
||||
}
|
||||
|
||||
//generate a userID
|
||||
const newUserID = generateUUID();
|
||||
//save this UUID
|
||||
chrome.storage.sync.set({
|
||||
"userID": newUserID,
|
||||
//the last video id loaded, to make sure it is a video id change
|
||||
"sponsorVideoID": null,
|
||||
"previousVideoID": null
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//gets the sponsor times from memory
|
||||
function getSponsorTimes(videoID, callback) {
|
||||
let sponsorTimes = [];
|
||||
let sponsorTimeKey = "sponsorTimes" + videoID;
|
||||
chrome.storage.sync.get([sponsorTimeKey], function(result) {
|
||||
let sponsorTimesStorage = result[sponsorTimeKey];
|
||||
if (sponsorTimesStorage != undefined && sponsorTimesStorage.length > 0) {
|
||||
sponsorTimes = sponsorTimesStorage;
|
||||
}
|
||||
|
||||
callback(sponsorTimes)
|
||||
});
|
||||
}
|
||||
|
||||
function addSponsorTime(time, videoID, callback) {
|
||||
getSponsorTimes(videoID, function(sponsorTimes) {
|
||||
//add to sponsorTimes
|
||||
if (sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length < 2) {
|
||||
//it is an end time
|
||||
sponsorTimes[sponsorTimes.length - 1][1] = time;
|
||||
} else {
|
||||
//it is a start time
|
||||
let sponsorTimesIndex = sponsorTimes.length;
|
||||
sponsorTimes[sponsorTimesIndex] = [];
|
||||
|
||||
sponsorTimes[sponsorTimesIndex][0] = time;
|
||||
}
|
||||
|
||||
//save this info
|
||||
let sponsorTimeKey = "sponsorTimes" + videoID;
|
||||
chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes}, callback);
|
||||
});
|
||||
}
|
||||
|
||||
function submitVote(type, UUID, callback) {
|
||||
chrome.storage.sync.get(["userID"], function(result) {
|
||||
let userID = result.userID;
|
||||
|
||||
//publish this vote
|
||||
sendRequestToServer("GET", "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp, error) {
|
||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||
callback({
|
||||
successType: 1
|
||||
});
|
||||
} else if (xmlhttp.readyState == 4 && xmlhttp.status == 405) {
|
||||
//duplicate vote
|
||||
callback({
|
||||
successType: 0,
|
||||
statusCode: xmlhttp.status
|
||||
});
|
||||
} else if (error) {
|
||||
//error while connect
|
||||
callback({
|
||||
successType: -1,
|
||||
statusCode: xmlhttp.status
|
||||
});
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function submitTimes(videoID, callback) {
|
||||
//get the video times from storage
|
||||
let sponsorTimeKey = 'sponsorTimes' + videoID;
|
||||
chrome.storage.sync.get([sponsorTimeKey, "userID"], function(result) {
|
||||
let sponsorTimes = result[sponsorTimeKey];
|
||||
let userID = result.userID;
|
||||
|
||||
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
|
||||
//submit these times
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
//submit the sponsorTime
|
||||
sendRequestToServer("GET", "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1]
|
||||
+ "&userID=" + userID, function(xmlhttp, error) {
|
||||
if (xmlhttp.readyState == 4 && !error) {
|
||||
callback({
|
||||
statusCode: xmlhttp.status
|
||||
});
|
||||
|
||||
if (xmlhttp.status == 200) {
|
||||
//add these to the storage log
|
||||
chrome.storage.sync.get(["sponsorTimesContributed"], function(result) {
|
||||
let currentContributionAmount = 0;
|
||||
if (result.sponsorTimesContributed != undefined) {
|
||||
//current contribution amount is known
|
||||
currentContributionAmount = result.sponsorTimesContributed;
|
||||
}
|
||||
|
||||
//save the amount contributed
|
||||
chrome.storage.sync.set({"sponsorTimesContributed": currentContributionAmount + sponsorTimes.length});
|
||||
});
|
||||
}
|
||||
} else if (error) {
|
||||
callback({
|
||||
statusCode: -1
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sendRequestToServer(type, address, callback) {
|
||||
let xmlhttp = new XMLHttpRequest();
|
||||
|
||||
xmlhttp.open(type, serverAddress + address, true);
|
||||
|
||||
if (callback != undefined) {
|
||||
xmlhttp.onreadystatechange = function () {
|
||||
callback(xmlhttp, false);
|
||||
};
|
||||
|
||||
xmlhttp.onerror = function(ev) {
|
||||
callback(xmlhttp, true);
|
||||
};
|
||||
}
|
||||
|
||||
//submit this request
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
function generateUUID(length = 36) {
|
||||
let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let result = "";
|
||||
let isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
|
||||
if (window.crypto && window.crypto.getRandomValues) {
|
||||
values = new Uint32Array(length);
|
||||
window.crypto.getRandomValues(values);
|
||||
for (i = 0; i < length; i++) {
|
||||
result += charset[values[i] % charset.length];
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += charset[Math.floor(Math.random() * charset.length)];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
//this file is loaded along iwth content.js
|
||||
//this file sets the server to connect to, and is gitignored
|
||||
var serverAddress = "https://sponsor.ajay.app";
|
||||
4
config.json.example
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"serverAddress": "https://sponsor.ajay.app",
|
||||
"serverAddressComment": "This specifies the default SponsorBlock server to conect to"
|
||||
}
|
||||
1067
content.js
10
crowdin.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
files:
|
||||
- source: /_locales/en/*
|
||||
translation: /_locales/%two_letters_code%/%original_file_name%
|
||||
languages_mapping:
|
||||
two_letters_code:
|
||||
pl-PL: "pl_PL"
|
||||
pr-BR: "pt_BR"
|
||||
pr-PT: "pt_PT"
|
||||
zh-CN: "zh_CH"
|
||||
zh-TW: "zh_TW"
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "sponsorBlocker@ajay.app",
|
||||
"strict_min_version": "57.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
8
jest.config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
"roots": [
|
||||
"src"
|
||||
],
|
||||
"transform": {
|
||||
"^.+\\.ts$": "ts-jest"
|
||||
},
|
||||
};
|
||||
@@ -1,68 +0,0 @@
|
||||
{
|
||||
"name": "__MSG_fullName__",
|
||||
"short_name": "__MSG_Name__",
|
||||
"version": "1.1.0",
|
||||
"default_locale": "en",
|
||||
"description": "__MSG_Description__",
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"https://*.youtube.com/*"
|
||||
],
|
||||
"all_frames": true,
|
||||
"js": [
|
||||
"config.js",
|
||||
"utils/previewBar.js",
|
||||
"utils/skipNotice.js",
|
||||
"utils.js",
|
||||
"content.js",
|
||||
"popup.js"
|
||||
],
|
||||
"css": [
|
||||
"content.css",
|
||||
"./libs/Source+Sans+Pro.css",
|
||||
"popup.css"
|
||||
]
|
||||
}
|
||||
],
|
||||
"web_accessible_resources": [
|
||||
"icons/LogoSponsorBlocker256px.png",
|
||||
"icons/IconSponsorBlocker256px.png",
|
||||
"icons/PlayerStartIconSponsorBlocker256px.png",
|
||||
"icons/PlayerStopIconSponsorBlocker256px.png",
|
||||
"icons/PlayerUploadIconSponsorBlocker256px.png",
|
||||
"icons/PlayerUploadFailedIconSponsorBlocker256px.png",
|
||||
"icons/upvote.png",
|
||||
"icons/downvote.png",
|
||||
"icons/report.png",
|
||||
"icons/close.png",
|
||||
"icons/PlayerInfoIconSponsorBlocker256px.png",
|
||||
"icons/PlayerDeleteIconSponsorBlocker256px.png",
|
||||
"popup.html"
|
||||
],
|
||||
"permissions": [
|
||||
"storage",
|
||||
"notifications",
|
||||
"https://sponsor.ajay.app/*"
|
||||
],
|
||||
"browser_action": {
|
||||
"default_title": "__MSG_Name__",
|
||||
"default_popup": "popup.html"
|
||||
},
|
||||
"background": {
|
||||
"scripts":[
|
||||
"utils.js",
|
||||
"config.js",
|
||||
"background.js"
|
||||
],
|
||||
"persistent": false
|
||||
},
|
||||
"icons": {
|
||||
"16": "icons/IconSponsorBlocker16px.png",
|
||||
"32": "icons/IconSponsorBlocker32px.png",
|
||||
"64": "icons/LogoSponsorBlocker64px.png",
|
||||
"128": "icons/LogoSponsorBlocker128px.png",
|
||||
"256": "icons/LogoSponsorBlocker256px.png"
|
||||
},
|
||||
"manifest_version": 2
|
||||
}
|
||||
4
manifest/beta-manifest-extra.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "BETA - SponsorBlock"
|
||||
}
|
||||
|
||||
8
manifest/chrome-manifest-extra.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"optional_permissions": [
|
||||
"declarativeContent"
|
||||
],
|
||||
"background": {
|
||||
"persistent": false
|
||||
}
|
||||
}
|
||||
8
manifest/firefox-beta-manifest-extra.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "sponsorBlockerBETA@ajay.app"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
7
manifest/firefox-manifest-extra.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "sponsorBlocker@ajay.app"
|
||||
}
|
||||
}
|
||||
}
|
||||
70
manifest/manifest.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "__MSG_fullName__",
|
||||
"short_name": "__MSG_Name__",
|
||||
"version": "1.2.22",
|
||||
"default_locale": "en",
|
||||
"description": "__MSG_Description__",
|
||||
"content_scripts": [{
|
||||
"run_at": "document_start",
|
||||
"matches": [
|
||||
"https://*.youtube.com/*",
|
||||
"https://www.youtube-nocookie.com/embed/*"
|
||||
],
|
||||
"all_frames": true,
|
||||
"js": [
|
||||
"./js/vendor.js",
|
||||
"./js/content.js"
|
||||
],
|
||||
"css": [
|
||||
"content.css",
|
||||
"./libs/Source+Sans+Pro.css",
|
||||
"popup.css"
|
||||
]
|
||||
}],
|
||||
"web_accessible_resources": [
|
||||
"icons/LogoSponsorBlocker256px.png",
|
||||
"icons/IconSponsorBlocker256px.png",
|
||||
"icons/PlayerStartIconSponsorBlocker256px.png",
|
||||
"icons/PlayerStopIconSponsorBlocker256px.png",
|
||||
"icons/PlayerUploadIconSponsorBlocker256px.png",
|
||||
"icons/PlayerUploadFailedIconSponsorBlocker256px.png",
|
||||
"icons/upvote.png",
|
||||
"icons/downvote.png",
|
||||
"icons/report.png",
|
||||
"icons/close.png",
|
||||
"icons/PlayerInfoIconSponsorBlocker256px.png",
|
||||
"icons/PlayerDeleteIconSponsorBlocker256px.png",
|
||||
"popup.html",
|
||||
"content.css"
|
||||
],
|
||||
"permissions": [
|
||||
"storage",
|
||||
"notifications",
|
||||
"https://sponsor.ajay.app/*"
|
||||
],
|
||||
"optional_permissions": [
|
||||
"*://*/*"
|
||||
],
|
||||
"browser_action": {
|
||||
"default_title": "__MSG_Name__",
|
||||
"default_popup": "popup.html"
|
||||
},
|
||||
"background": {
|
||||
"scripts":[
|
||||
"./js/vendor.js",
|
||||
"./js/background.js"
|
||||
]
|
||||
},
|
||||
"icons": {
|
||||
"16": "icons/IconSponsorBlocker16px.png",
|
||||
"32": "icons/IconSponsorBlocker32px.png",
|
||||
"64": "icons/LogoSponsorBlocker64px.png",
|
||||
"128": "icons/LogoSponsorBlocker128px.png",
|
||||
"256": "icons/LogoSponsorBlocker256px.png"
|
||||
},
|
||||
"options_ui": {
|
||||
"page": "options/options.html",
|
||||
"open_in_tab": true
|
||||
},
|
||||
"manifest_version": 2
|
||||
}
|
||||
12847
package-lock.json
generated
Normal file
50
package.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "sponsorblock",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "background.js",
|
||||
"dependencies": {
|
||||
"concurrently": "^5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"web-ext": "^4.0.0",
|
||||
"@types/chrome": "0.0.91",
|
||||
"@types/firefox-webext-browser": "70.0.1",
|
||||
"@types/jest": "^24.0.23",
|
||||
"@types/jquery": "^3.3.31",
|
||||
"copy-webpack-plugin": "^5.0.5",
|
||||
"jest": "^24.9.0",
|
||||
"ts-jest": "^24.2.0",
|
||||
"rimraf": "^3.0.0",
|
||||
"ts-loader": "^6.2.1",
|
||||
"typescript": "~3.7.3",
|
||||
"webpack": "~4.41.2",
|
||||
"webpack-cli": "~3.3.10",
|
||||
"webpack-merge": "~4.2.2"
|
||||
},
|
||||
"scripts": {
|
||||
"web-run": "npm run web-run:chrome",
|
||||
"web-run:firefox": "cd dist && web-ext run --start-url https://addons.mozilla.org/firefox/addon/ublock-origin/",
|
||||
"web-run:chrome": "cd dist && web-ext run --start-url https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm -t chromium",
|
||||
"build": "npm run build:chrome",
|
||||
"build:chrome": "webpack --env.browser=chrome --config webpack/webpack.prod.js",
|
||||
"build:firefox": "webpack --env.browser=firefox --config webpack/webpack.prod.js",
|
||||
"build:dev": "npm run build:dev:chrome",
|
||||
"build:dev:chrome": "webpack --env.browser=chrome --config webpack/webpack.dev.js",
|
||||
"build:dev:firefox": "webpack --env.browser=firefox --config webpack/webpack.dev.js",
|
||||
"build:watch": "npm run build:watch:chrome",
|
||||
"build:watch:chrome": "webpack --env.browser=chrome --config webpack/webpack.dev.js --watch",
|
||||
"build:watch:firefox": "webpack --env.browser=firefox --config webpack/webpack.dev.js --watch",
|
||||
"dev": "npm run build:dev && concurrently \"npm run web-run\" \"npm run build:watch\"",
|
||||
"dev:firefox": "npm run build:dev:firefox && concurrently \"npm run web-run:firefox\" \"npm run build:watch:firefox\"",
|
||||
"clean": "rimraf dist",
|
||||
"test": "npx jest"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/ajayyy/SponsorBlock.git"
|
||||
},
|
||||
"author": "Ajay Ramachandran",
|
||||
"license": "GPL-3.0-only",
|
||||
"private": true
|
||||
}
|
||||
233
popup.html
@@ -1,233 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>SponsorBlock Popup</title>
|
||||
<link id="sponorBlockPopupFont" rel="stylesheet" type="text/css" href="/libs/Source+Sans+Pro.css"/>
|
||||
<link id="sponorBlockStyleSheet" rel="stylesheet" type="text/css" href="popup.css"/>
|
||||
</head>
|
||||
|
||||
<body class="popupBody">
|
||||
<center>
|
||||
<div id="app" class="popupBody">
|
||||
<img src="icons/LogoSponsorBlocker256px.png" height="64px" id="sponsorBlockPopupLogo"/>
|
||||
|
||||
<h1 class="popupElement">SponsorBlock</h1>
|
||||
|
||||
<!-- Loading text -->
|
||||
<p id="loadingIndicator" class="popupElement">Loading...</p>
|
||||
|
||||
<!-- Hidden until loading complete -->
|
||||
<div id="mainControls" class="main popupElement" style="display: none">
|
||||
<!-- If the video was found in the database -->
|
||||
<div id="videoFound">
|
||||
|
||||
</div>
|
||||
|
||||
<div id="downloadedSponsorMessageTimes" class="popupElement">
|
||||
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<div>
|
||||
<button id="whitelistChannel" class="whitelistButton popupElement">Whitelist Channel</button>
|
||||
<button id="unwhitelistChannel" class="whitelistButton popupElement" style="display: none">Remove Channel From Whitelist</button>
|
||||
</div>
|
||||
<sub class="popupElement">
|
||||
Whitelist the channels who do sponsorships ethically to encourage good behavior, or maybe if they are just entertaining and funny. Or don't, that's your call.
|
||||
</sub>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="reportAnIssue" class="dangerButton popupElement">Vote On A Sponsor Time</button>
|
||||
|
||||
<div id="issueReporterContainer" class="popupElement" style="display: none">
|
||||
|
||||
<h3 style="margin-top: 0px" class="popupElement">Vote On A Sponsor Time</h3>
|
||||
|
||||
<div id="issueReporterTimeButtons" class="popupElement">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<h2 class="recordingSubtitle popupElement">Record the times of a sponsorship</h2>
|
||||
|
||||
<p class="popupElement">
|
||||
<span id=sponsorTimesContributionsContainer class="popupElement" style="display: none">
|
||||
So far, you've submitted
|
||||
<span id="sponsorTimesContributionsDisplay" class="popupElement">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimesContributionsDisplayEndWord" class="popupElement">
|
||||
sponsors.
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span id=sponsorTimesViewsContainer class="popupElement" style="display: none">
|
||||
You have saved people from
|
||||
<span id="sponsorTimesViewsDisplay" class="popupElement">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimesViewsDisplayEndWord" class="popupElement">
|
||||
sponsor segments.
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<div class="popupElement">
|
||||
View the leaderboard <a class="popupElement discreteLink" href="https://sponsor.ajay.app/stats" target="_blank">here</a>.
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<p class="popupElement">
|
||||
Click the button below when the sponsorship starts and ends to record and
|
||||
submit it to the database.
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<button id="sponsorStart" class="greenButton popupElement">Sponsorship Starts Now</button>
|
||||
</div>
|
||||
|
||||
<sub class="popupElement">Hint: Press the semicolon key while focused on a video report the start/end of a sponsor and quote to submit.</sub>
|
||||
|
||||
<div id="submissionSection" class="popupElement" style="display: none">
|
||||
<h3 class="popupElement">Latest Sponsor Message Times Chosen</h3>
|
||||
<b>
|
||||
<div id="sponsorMessageTimes" class="popupElement">
|
||||
|
||||
</div>
|
||||
</b>
|
||||
|
||||
<br/>
|
||||
|
||||
<button id="clearTimes" class="smallButton popupElement">Clear Times</button>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div id="submitTimesContainer" class="popupElement" style="display: none">
|
||||
<button id="submitTimes" class="smallButton popupElement">Submit Times</button>
|
||||
|
||||
<div id="submitTimesInfoMessageContainer" class="popupElement" style="display: none">
|
||||
<h3 id="submitTimesInfoMessage" class="popupElement">
|
||||
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="setUsernameContainer" class="popupElement">
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="setUsernameButton" class="warningButton popupElement">Set Username</button>
|
||||
<br/>
|
||||
<sub class="popupElement">
|
||||
This is used on the public stats page to show off how much you've contributed. See it <a class="popupElement discreteLink" href="https://sponsor.ajay.app/stats" target="_blank">here</a>.
|
||||
</sub>
|
||||
</div>
|
||||
|
||||
<div id="setUsername" class="popupElement" style="display: none">
|
||||
<br/>
|
||||
|
||||
<h3>Set Username</h3>
|
||||
|
||||
<div id="setUsernameStatusContainer" style="display: none">
|
||||
<h2 id="setUsernameStatus"></h2>
|
||||
</div>
|
||||
|
||||
|
||||
<input id="usernameInput" hint="Username"></input>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="submitUsername" class="warningButton popupElement">Submit Username</button>
|
||||
</div>
|
||||
|
||||
<div id="discordButtonContainer" class="popupElement" style="display: none">
|
||||
<br/>
|
||||
|
||||
<a href="https://discord.gg/QnmVMpU" class="popupElement" target="_blank"><img src="https://www.logolynx.com/images/logolynx/1b/1bcc0f0aefe71b2c8ce66ffe8645d365.png" height="32px"/></a>
|
||||
|
||||
<br/>
|
||||
|
||||
Come join the official discord server to give suggestions and feedback!
|
||||
|
||||
<br/>
|
||||
|
||||
<span id="hideDiscordButton" class="smallLink popupElement">Hide this</span>
|
||||
</div>
|
||||
|
||||
<div id="optionsButtonContainer" class="popupElement">
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="optionsButton" class="dangerButton popupElement">Options</button>
|
||||
</div>
|
||||
|
||||
<div id="options" class="popupElement" style="display: none">
|
||||
<br/>
|
||||
|
||||
<h3>Options</h3>
|
||||
|
||||
<button id="hideVideoPlayerControls" class="warningButton popupElement">Hide Buttons On YouTube Player</button>
|
||||
<button id="showVideoPlayerControls" style="display: none" class="warningButton popupElement">Show Buttons On YouTube Player</button>
|
||||
<br/>
|
||||
<sub class="popupElement">
|
||||
This hides the buttons that appear on the YouTube player to submit sponsors. I can see this being annoying for some
|
||||
people. Instead of using the button there, this popup can be used to submit sponsors. To hide the notice that appears,
|
||||
use the button that appears on the notice saying "Don't show this again". You can always enable these settings again
|
||||
later.
|
||||
</sub>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="hideInfoButtonPlayerControls" class="warningButton popupElement">Hide Info Button On YouTube Player</button>
|
||||
<button id="showInfoButtonPlayerControls" style="display: none" class="warningButton popupElement">Show Info Button On YouTube Player</button>
|
||||
<br/>
|
||||
<sub class="popupElement">
|
||||
This is the button that opens up a popup in the YouTube page.
|
||||
</sub>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="hideDeleteButtonPlayerControls" class="warningButton popupElement">Hide Delete Button On YouTube Player</button>
|
||||
<button id="showDeleteButtonPlayerControls" style="display: none" class="warningButton popupElement">Show Delete Button On YouTube Player</button>
|
||||
<br/>
|
||||
<sub class="popupElement">
|
||||
This is the button that allows you to clear all sponsors on the YouTube player.
|
||||
</sub>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="disableSponsorViewTracking" class="warningButton popupElement">Disable Sponsor View Tracking</button>
|
||||
<button id="enableSponsorViewTracking" style="display: none" class="warningButton popupElement">Enable Sponsor View Tracking</button>
|
||||
<br/>
|
||||
<sub class="popupElement">
|
||||
This feature tracks which sponsors you have skipped to let users know how much their submission has helped others and
|
||||
used as a metric along with upvotes to ensure that spam doesn't get into the database. The extension sends a message
|
||||
to the server each time you skip a sponsor. Hopefully most people don't change this setting so that the view numbers
|
||||
are accurate. :)
|
||||
</sub>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="showNoticeAgain" style="display: none" class="dangerButton popupElement">Show Notice Again</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
<!-- Scripts that need to load after the html -->
|
||||
<script src="config.js"></script>
|
||||
<script src="utils.js"></script>
|
||||
<script src="popup.js"></script>
|
||||
</html>
|
||||
318
public/_locales/de/messages.json
Normal file
@@ -0,0 +1,318 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock for YouTube - Skip Sponsorships",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Überspringe die gesponserten Inhalte in YouTube-Videos. Melde gesponsorte Inhalte in den von dir angesehenen Videos und erspare anderen die Zeit.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Ungültige Anforderung"
|
||||
},
|
||||
"429": {
|
||||
"message": "Du hast zu viele Segmente in diesem Video eingereicht. Bist du dir sicher?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Dieser Inhalt wurde bereits eingereicht."
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Kanal auf Whitelist gesetzt!"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "Sponsor"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "Sponsoren"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "gesponsorter Inhalt"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "gesponsorte Inhalte"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Sponsor übersprungen"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Melden"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Melde dieses Segment als unzulässig."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Abbrechen"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Laden..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuten"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekunden"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Verstecken"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Klicke Zurück um die Aktion rückgängig zu machen."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Zurück"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Vorwärts"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Pausiert"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "\n\nUm einzelne Werte zu löschen oder zu ändern, klicke auf den Info-Button, oder öffne die Erweiterungs-Übersicht, indem du das Erweiterungssymbol in der rechten oberen Ecke anklickst."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Bist du sicher, dass du Folgendes löschen möchtest?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Deine Segmente konnten nicht gesendet werden, bitte versuche es später erneut."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Die gesponsorten Inhalte dieses Videos befinden sich bereits in der Datenbank!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Keine Sponsoren gefunden"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Gesponserter Inhalt beginnt"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Gesponserter Inhalt endet"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Keine YouTube-Videos in diesem Tab gefunden. Wenn dies ein Youtube-Tab ist, schließe dieses Pop-up und öffne es erneut. Wenn das nicht hilft, versuche den Tab neu zu laden."
|
||||
},
|
||||
"success": {
|
||||
"message": "Erfolg!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Abgestimmt!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Du hast bereits so abgestimmt."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Der Server ist scheinbar offline. Bitte unverzüglich dem Entwickler melden."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Ein Verbindungsfehler ist aufgetreten. Fehlermeldung: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Möchtest du die Segmente für die Video ID senden?"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Scheinbar hast du einige Segmente noch nicht gesendet. Kehre zur Seite zurück um sie zu senden (sie sind noch gespeichert)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Lösche Auswahl"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Öffne SponsorBlock-Popup"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Sende Auswahl"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Bist du sicher, dass die Auswahl abgeschickt werden soll?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Kanal auf Whitelist setzen "
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Kanal von Whitelist entfernen"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Stimme für Zeiten ab"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Lege das Zeitfenster eines gesponsorten Inhalts fest"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Gemeldet wurden von dir bisher"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Du hast andere Benutzer bewahrt vor"
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Siehe Rangliste"
|
||||
},
|
||||
"here": {
|
||||
"message": "hier"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Klicke den Knopf unten, wenn der gesponsorte Inhalt beginnt und endet, um aufzunehmen und\n einzusenden"
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Hinweis: In den Optionen lässt sich eine Taste für das Festlegen von Anfang/Ende des gesponsorten Inhalts, sowie für das Einsenden festlegen"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Letzte ausgewählte Zeitabschnitte"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Zeiten löschen"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Zeiten einsenden"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Dies ist wichtig für die öffentliche Nutzerstatistik. Siehe"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Alias festlegen"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Tritt dem offiziellen Discord-Kanal bei und teile Anregungen und Feedback!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Verstecken"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Optionen"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Knöpfe in YouTube-Leiste zeigen"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Knöpfe in YouTube-Leiste verstecken"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Die Einstellung versteckt den Einsende-Knopf in der Youtube-Leiste. Ich kann verstehen, weshalb manchen diese Funktion\n an dieser Stelle stört. Stattdessen kann dafür dieses Pop-up genutzt werden. Um die transparente Benachrichtigung zu verstecken, klicke auf den \"Verstecken\"-Knopf \n der Benachrichtigung. Diese Einstellungen können wieder rückgängig gemacht werden."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Zeige Info-Knopf in Youtube-Leiste"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Verstecke Info-Knopf in Youtube-Leiste"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Dieser Knopf öffnet ein Pop-up auf der Youtube-Seite."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Verstecke Löschen-Knopf in Youtube Leiste"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Zeige Löschen-Knopf in Youtube Leiste"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Dieser Knopf entfernt sämtlich Segmente in der Youtube-Zeitleiste."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Deaktiviere das Mitzählen übersprungener Sponsoren"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Aktiviere das Mitzählen übersprungener Sponsoren"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Diese Funktion hält fest, welche Sponsoren von dir übersprungen wurden und hilft anderen zu erfahren, was ihre Einsendungen bewirkt haben.\n Außerdem dienen die Werte zusammen mit positiven Rückmeldungen als Anti-Spam-Schutz. \n Wenn ein gesponsorter Inhalt übersprungen wird, sendet die Erweiterung eine Nachricht an den Server. \n Hoffentlich wird diese Funktion auch weiterhin genutzt, damit der Algorithmus funktioniert. :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Benachrichtigung wieder zeigen"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock ist eine Erweiterung, die gesponsorte Segmente in YouTube-Videos überspringt. SponsorBlock ist ein Benutzernetzwerk, bei dem jeder Anfang und Ende eines Werbeblocks einreichen kann. Sobald die Information von einem Nutzer eingereicht wurde, überspringen die Erweiterungen der anderen dieses Segment automatisch.",
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Webseite",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Quellcode",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "Die Benachrichtigung wurde verbessert!",
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Gefällt dir immer noch nicht? Dann klicke den Verstecken-Knopf.",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Segment aufnehmen Taste festlegen"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Segment einsenden Taste festlegen"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Taste drücken, um festzulegen"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "Die Taste wurde festgelegt auf: "
|
||||
},
|
||||
"0": {
|
||||
"message": "Verbindungsüberschreibung. Überprüfe deine Internetverbindung. Bist du mit dem Internet verbunden, ist der Server wahrscheinlich offline."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "SponsorBlock ausschalten"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "SponsorBlock einschalten"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Deine Statistik",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"502": {
|
||||
"message": "Der Server scheint überlastet zu sein. Probiere es in ein paar Sekunden erneut."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Fehlermeldung: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Sponsor überspringen?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Überspringen"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Auto-Überspringen deaktivieren"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Auto-Überspringen aktivieren"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "Auto-Überspringen überspringt gesponsorte Inhalte für dich. Wenn deaktiviert, fragt die Benachrichtigung, ob übersprungen werden soll."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Du übersprangst "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Du erspartest dir "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "Minute"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "Minuten"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "Stunde"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "Stunden"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Du erspartest anderen"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " ihrer Zeit."
|
||||
}
|
||||
}
|
||||
444
public/_locales/en/messages.json
Normal file
@@ -0,0 +1,444 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock for YouTube - Skip Sponsorships",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Skip over sponsorship on YouTube videos. Report sponsors on videos you watch to save the time of others.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Server said this request was invalid"
|
||||
},
|
||||
"429": {
|
||||
"message": "You have submitted too many sponsor times for this one video, are you sure there are this many?"
|
||||
},
|
||||
"409": {
|
||||
"message": "This has already been submitted before"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Channel Whitelisted!"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "sponsor"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "sponsors"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "sponsor segment"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "sponsor segments"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Sponsor Skipped"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Report"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Report this sponsor submission as incorrect."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Dismiss"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Loading..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minutes"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Seconds"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Never Show"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Hit unskip to get to where you came from."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Unskip"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Reskip"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Paused"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "To edit or delete individual values, click the info button or open the extension popup by clicking the extension icon in the top right corner."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Are you sure you want to clear this?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "There was an error submitting your sponsor times, please try again later."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "This video's sponsors are in the database!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "No sponsors found"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Sponsorship Starts Now"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Sponsorship Ends Now"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "No YouTube video found at this tab. If you know this is a YouTube tab, close this popup and open it again. If that does not work, try reloading the tab."
|
||||
},
|
||||
"success": {
|
||||
"message": "Success!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Voted!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "You have already voted this way before."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "It seems the sever is down. Contact the dev immediately."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "A connection error has occured. Error code: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Do you want to submit the sponsor times for video id"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "You seem to have left some sponsor times unsubmitted. Go back to that page to submit them (they are not deleted)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Clear Sponsor Times"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Open SponsorBlock Popup"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Submit Sponsor Times"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Are you sure you want to submit this?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Whitelist Channel"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Remove Channel From Whitelist"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Vote On A Sponsor Time"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Record the times of a sponsorship"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "So far, you've submitted"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "You have saved people from "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "View the leaderboard"
|
||||
},
|
||||
"here": {
|
||||
"message": "here"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Click the button below when the sponsorship starts and ends to record and\nsubmit it to the database."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Hint: Press the semicolon key while focused on a video to report the start/end of a sponsor and quote to submit. (This can be changed in the options)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Latest Sponsor Message Times Chosen"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Clear Times"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Submit Times"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "This is used on the public stats page to show off how much you've contributed. See it"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Set Username"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Come join the official discord server to give suggestions and feedback!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Hide this"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Options"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Show Buttons On YouTube Player"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Hide Buttons On YouTube Player"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "This hides the buttons that appear on the YouTube player to submit sponsors. I can see this being annoying for some\n people. Instead of using the button there, this popup can be used to submit sponsors. To hide the notice that appears, \n use the button that appears on the notice saying \"Don't show this again\". You can always enable these settings again later."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Show Info Button On YouTube Player"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Hide Info Button On YouTube Player"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "This is the button that opens up a popup in the YouTube page."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Hide Delete Button On YouTube Player"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Show Delete Button On YouTube Player"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "This is the button that allows you to clear all sponsors on the YouTube player."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Disable Sponsor Skip Count Tracking"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Enable Sponsor Skip Count Tracking"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "This feature tracks which sponsors you have skipped to let users know how much their submission has helped others and\nused as a metric along with upvotes to ensure that spam doesn't get into the database. The extension sends a message\nto the server each time you skip a sponsor. Hopefully most people don't change this setting so that the view numbers are accurate. :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Show Notice Again"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock is an extension that will skip over sponsored segments of YouTube videos. SponsorBlock is a crowdsourced browser extension that lets anyone submit the start and end times of sponsored segments of YouTube videos. Once one person submits this information, everyone else with this extension will skip right over the sponsored segment.",
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Website",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Source Code",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "The notice has been upgraded!",
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "If you still don't like it, hit the never show button.",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Set key for start sponsor keybind"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Set key for submission keybind"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Select a key by typing it"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "The keybind has been set to: "
|
||||
},
|
||||
"0": {
|
||||
"message": "Connection Timeout. Check your internet connection. If your internet is working, the server is probably overloaded or down."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Disable SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Enable SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Your Work",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"502": {
|
||||
"message": "The server seems to be overloaded. Try again in a few seconds."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Error Code: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Skip Sponsor?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Skip"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Disable Auto Skip"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Enable Auto Skip"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "Auto skip will skip sponsors for you. If disabled, a notice will appear asking if you'd like to skip."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "You have skipped "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "You have saved yourself "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "minute"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "minutes"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "hour"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "hours"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "You have saved people"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " of their lives."
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- Make sure your segment only contains paid promotion segment, nothing else.\n- Make sure skipping this segment will not skip valuable content\n- If the whole video is a sponsor, please do not report it. A full video reporting system will come out soon.\n- Please do not report disclaimers that could show bias (if a review video is sponsored, don't skip when they mention that)."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Check status.sponsor.ajay.app for server status."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Import/Export Your UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "This should be kept private. This is like a password and should not be shared with anyone. If someone has this, they can impersonate you."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Set UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Warning: Changing the UserID is permanent. Are you sure you would like to do this? Make sure to backup your old one just in case."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Created By"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Auto Skip"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Show Notice After A Sponsor Is Skipped"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". It is currently set to:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Support Invidious"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) is a third party YouTube client. To enable support, you must accept the extra permissions. This does NOT work in incongnito on Chrome and other Chromium variants."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Enable Invidious support, disable autoskip, hide buttons and more."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Add Invidious Instance"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Add a custom instance of Invidious. This must be formatted with JUST the domain. Example: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Add"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "This is an invalid domain. This should JUST include the domain part. Example: invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Reset Invidious Instance List"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "You are about to reset the Invidious instance list"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Current Instances:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Auto Upvote"
|
||||
},
|
||||
"whatAutoUpvote": {
|
||||
"message": "With this enabled, the extension will upvote all submissions you view if you do not report them. If the notice is disabled, this will not occur."
|
||||
},
|
||||
"minDuration": {
|
||||
"message": "Minimum duration (seconds):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Sponsor segments shorter than the set value will not be skipped or show in the player."
|
||||
},
|
||||
"shortCheck": {
|
||||
"message": "The following submission is shorter than your minimum duration option. This could mean that this is already submitted, and just being ignored due to this option. Are you sure you would like to submit?"
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "Show Upload Button"
|
||||
},
|
||||
"whatUploadButton": {
|
||||
"message": "This button appears on the YouTube player after you have selected a timestamp and are ready to submit."
|
||||
},
|
||||
"customServerAddress": {
|
||||
"message": "SponsorBlock Server Address"
|
||||
},
|
||||
"customServerAddressDescription": {
|
||||
"message": "The address SponsorBlock uses to make calls to the server.\nUnless you have your own server instance, this should not be changed."
|
||||
},
|
||||
"save": {
|
||||
"message": "Save"
|
||||
},
|
||||
"reset": {
|
||||
"message": "Reset"
|
||||
},
|
||||
"customAddressError": {
|
||||
"message": "This address is not in the right form. Make sure you have http:// or https:// at the begining and no trailing slashes."
|
||||
},
|
||||
"areYouSureReset": {
|
||||
"message": "Are you sure you would like to reset this?"
|
||||
},
|
||||
"confirmPrivacy": {
|
||||
"message": "The video has been detected as unlisted. Click cancel if you do not want to check for sponsors."
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Ignore Unlisted Videos"
|
||||
},
|
||||
"whatUnlistedCheck": {
|
||||
"message": "This setting will significantly slow down SponsorBlock. Sponsor lookups require sending the video ID to the server. If you are concerned about unlisted video IDs being sent over the internet, enable this option."
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "m.youtube.com is now supported"
|
||||
},
|
||||
"exportOptions": {
|
||||
"message": "Import/Export All Options"
|
||||
},
|
||||
"whatExportOptions": {
|
||||
"message": "This is your entire configuration in JSON. This includes your userID, so be sure to share this wisely."
|
||||
},
|
||||
"setOptions": {
|
||||
"message": "Set Options"
|
||||
},
|
||||
"exportOptionsWarning": {
|
||||
"message": "Warning: Changing the options is permanent and can break your install. Are you sure you would like to do this? Make sure to backup your old one just in case."
|
||||
},
|
||||
"incorrectlyFormattedOptions": {
|
||||
"message": "This JSON is not formatted correctly. Your options have not been changed."
|
||||
}
|
||||
}
|
||||
263
public/_locales/fr/messages.json
Normal file
@@ -0,0 +1,263 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock pour YouTube - Supprime les messages commerciaux et publicités intégrées",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Passe automatiquement les messages commerciaux intégrés dans les vidéos YouTube. Soumettez les segments commerciaux dans les vidéos que vous regardez pour aidez les autres.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Soumission invalide"
|
||||
},
|
||||
"429": {
|
||||
"message": "Vous cherchez à envoyer beaucoup de segments, y en a-t-il vraiment autant ?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Déja soumis"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Cette chaîne est sur la liste blanche !"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "message commercial"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "messages commerciaux"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "segment commercial"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "segments commerciaux"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Message commercial passé"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Incorrect"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Signaler que ce segment commercial est incorrect ou n'existe pas."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Fermer"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Chargement en cours..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minutes"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Secondes"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Ne plus montrer"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Cliquez sur revenir en arrière pour revenir avant le saut du segment commercial"
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Revenir en arrière"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Sauter"
|
||||
},
|
||||
"paused": {
|
||||
"message": "En pause"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "\n\nPour modifier ou supprimer des soumissions, cliquez sur le bouton d'info ou ouvrez la fenêtre de l'extension en cliquant sur son icône dans le coin en haut à droite."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Êtes-vous certain(e) de vouloir supprimer vos soumissions ?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Une erreur s'est produite lors de la soumission, veuillez ré-essayer plus tard."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Les messages commerciaux sont déjà dans notre base de donnée pour cette vidéo !"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Pas de messages commerciaux trouvés"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Début du message commercial"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Fin du message commercial"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Ceci n'est pas un onglet YouTube, ou vous avez cliqué trop tôt. \n Si vous êtes sûr(e) que c'est un onglet YouTube, fermez cette fenêtre et réessayez."
|
||||
},
|
||||
"success": {
|
||||
"message": "Succès !"
|
||||
},
|
||||
"voted": {
|
||||
"message": "A voté !"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Vous avez déjà voté pour ce choix."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Le serveur ne fonctionne pas. Contactez le développeur."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Erreur de connexion. Code d'erreur : "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Voulez-vous soumettre les segments commerciaux pour cette vidéo"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Vous avez laissé des segments commerciaux non soumis. Retournez sur la vidéo pour les soumettre (ils ont été conservés)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Supprimer les segments commerciaux"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Ouvrir l'encart SponsorBlock"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Soumettre les segments commerciaux"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Êtes-vous sûr de vouloir soumettre ces segments?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Ajouter la chaîne à la liste blanche"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Supprimer la chaîne de la liste blanche"
|
||||
},
|
||||
"whitelistDescription": {
|
||||
"message": "Ajouter à la liste blanche les chaînes qui publient des messages commerciaux de façon éthique pour encourager les bons comportements, ou qui publient des messages commerciaux divertissants ou drôles. Ou pas, c'est votre choix."
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Voter sur un segment commercial"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Enregistrer un segment commercial"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Vous avez soumis jusqu'à présent"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Vous avez fait gagner aux autres "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Consulter le classement"
|
||||
},
|
||||
"here": {
|
||||
"message": "ici"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Cliquez sur le bouton ci-dessous quand le segment commercial commence puis \nse termine pour l'enregistrer et le soumettre à la base de données."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Astuce : utilisez la touche point-virgule lorsque la vidéo est sélectionnée pour enregistrer le début et la fin d'un segment commercial; utilisez la touche guillemet pour le soumettre. (Les touches peuvent être modifiées dans les options)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Derniers temps choisis pour le segment commercial"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Supprimer les temps"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Soumettre les temps"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Affiché sur le classement public pour montrer vos contributions. Voir sur"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Choisir pseudo"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Rejoignez le serveur Discord officiel pour toutes suggestions ou remarques!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Cacher"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Options"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Montrer les boutons sur le lecteur YouTube"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Cacher les boutons sur le lecteur YouTube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Cela permet de cacher du lecteur YouTube les boutons utilisés pour soumettre des segments commerciaux. Je peux \ncomprendre que certaines personnes les trouvent perturbants. Au lieu d'utiliser ces boutons, cette fenêtre peut être utilisée \npour soumettre des segments commerciaux. Pour cacher la notification, utilisez le bouton \"Ne plus montrer\" sur la notification. Vous pouvez toujours réactiver ces paramètres plus tard."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Montrer le bouton Info sur le lecteur YouTube"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Cacher le bouton Info sur le lecteur YouTube"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Il s'agit du bouton qui ouvre l'encart sur la page YouTube."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Cacher le bouton Supprimer sur le lecteur YouTube"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Montrer le bouton Supprimer sur le lecteur YouTube"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Il s'agit du bouton qui permet de supprimer tous les segments commerciaux depuis le lecteur YouTube."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Désactiver le suivi des vues de segments commerciaux"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Activer le suivi des vues de segments commerciaux"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Cette fonctionnalité suit quels segments commerciaux vous avez sautés afin de calculer le bénéfice des soumissions des \nautres utilisateurs. Elle est également utilisée comme métrique, avec les haut-votes, afin de s'assurer que les spams \nsont ignorés. L'extension envoie un message au serveur à chauqe fois qu'un segment commercial est sauté. Avec un peu de chance, peu de personnes désactiveront cette fonctionnalité afin d'obtenir des nombres de vues exacts. :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Afficher la notification"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock est une extension qui permet de passer les messages commerciaux des vidéos YouTube. SponsorBlock est une extension pour navigateur basée sur le crowdsourcing permettant à n'importe qui de soumettre le début et la fin des segments commerciaux sur les vidéos YouTube. Dès qu'une personne a soumis ces informations, les autres utilisateurs de l'extension en bénéficieront et verront les messages commerciaux automatiquement sautés.",
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Site web",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Code source",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "La notification a été mise à jour !",
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Si elle ne vous plaît pas, cliquez sur le bouton \"Ne plus montrer\"",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Changer le raccourci pour enregistrer un segment"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Changer le raccourci pour soumettre les segments"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Appuyez sur une touche"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "Le raccourci choisi est : "
|
||||
}
|
||||
}
|
||||
244
public/_locales/it/messages.json
Normal file
@@ -0,0 +1,244 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock per YouTube - Salta gli sponsor",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Salta i contenuti sponsorizzati nei video di YouTube. Segnala gli annunci incorporati nei video che guardi per far risparmiare tempo agli altri.",
|
||||
"description": "Description of the extension."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Richiesta non valida"
|
||||
},
|
||||
"429": {
|
||||
"message": "Stai inviando troppi spezzoni per questo video, sei sicuro che ce ne siano così tanti?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Questo spezzone è già stato inviato"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Canale aggiunto alla whitelist!"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "sponsorizzazione"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "sponsorizzazioni"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "spezzone sponsorizzato"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "spezzoni sponsorizzati"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Sponsorizzazione Saltata"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Segnala"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Segnala questo spezzone come non corretto."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Chiudi"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Caricamento..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuti"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Secondi"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Non mostrare più"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Premi non saltare per tornare da dove sei venuto."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Non saltare"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Salta ancora"
|
||||
},
|
||||
"paused": {
|
||||
"message": "In pausa"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "\n\nPer modificare o eliminare valori specifici, premi il pulsante delle informazioni o apri il popup cliccando l'icona dell'estensione nell'angolo in alto a destra."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Sei sicuro di volerlo cancellare?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Si è verificato un errore durante l'invio dello spezzone sponsorizzato, per favore riprova più tardi."
|
||||
},
|
||||
|
||||
"sponsorFound": {
|
||||
"message": "I contenuti sponsorizzati di questo video sono nel database!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Nessuna sponsorizzazione trovata"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "La sponsorizzazione inizia adesso"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "La sponsorizzazione finisce adesso"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Probabilmente questa non è una scheda di YouTube, oppure hai cliccato troppo presto. \nSe sei sicuro di essere in una scheda di YouTube,\n riapri questo popup."
|
||||
},
|
||||
"success": {
|
||||
"message": "Successo!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Votato!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Hai già votato."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Sembra che il server non funzioni. Contatta subito lo sviluppatore."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Si è verificato un errore durante la connessione. Codice errore: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Vuoi inviare gli spezzoni sponsorizzati per il video con id"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Sembra che tu non abbia inviato alcuni spezzoni sponsorizzati. Ritorna alla pagina precedente per inviarli (non sono stati eliminati)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Cancella gli Spezzoni Sponsorizzati"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Apri il Popup di SponsorBlock"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Invia gli Spezzoni Sponsorizzati"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Sei sicuro di volerlo inviare?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Aggiungi Canale alla Whitelist"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Rimuovi Canale dalla Whitelist"
|
||||
},
|
||||
"whitelistDescription": {
|
||||
"message": "Aggiungi alla whitelist i canali che sponsorizzano eticamente per incoraggiare ad un comportamento corretto, oppure se sono semplicemente intrattenenti e divertenti. Oppure non farlo, decidi tu."
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Vota uno Spezzone Sponsorizzato"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Registra uno Spezzone Sponsorizzato"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Fino ad ora hai inviato"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Hai salvato le persone da "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Guarda la classifica"
|
||||
},
|
||||
"here": {
|
||||
"message": "qui"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Premi il pulsante qui sotto quando inizia e finisce la sponsorizzazione per registrarla e\ninviarla al database."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Suggerimento: Premi il tasto punto e virgola mentre il video è attivo per segnalare l'inizio/fine di una sponsorizzazione e virgolette per inviare."
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Ultimi minutaggi sponsorizzati scelti"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Cancella Minutaggi"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Invia Minutaggi"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Viene utilizzato nelle pagine delle statistiche pubbliche che mostrano quanto hai contribuito. Vedi"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Imposta Username"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Entra nel server Discord ufficiale per darci suggerimenti e feedback!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Nascondi"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Opzioni"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Mostra i Pulsanti nel Lettore di YouTube"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Nascondi i Pulsanti nel Lettore di YouTube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Nasconde i pulsanti che appaiono nel lettore di YouTube per inviare spezzoni sponsorizzati. Capisco che può essere fastidioso per alcune\n persone. Invece di utilizzare quei pulsanti, è possibile utilizzare questo popup per inviare gli spezzoni sponsorizzati. Per nascondere l'avviso che appare, \nusa il bottone \"Non mostrare più\" nell'avviso. Potrai sempre abilitare nuovamente queste impostazioni in futuro."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Mostra il Pulsante Informazioni nel Lettore di YouTube"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Nascondi il Pulsante Informazioni nel Lettore di YouTube"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Questo è il pulsante che apre un popup nella pagina YouTube."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Nascondi il Pulsante Elimina nel Lettore di YouTube"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Mostra il Pulsante Elimina nel Lettore di YouTube"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Questo è il pulsante che ti permette di cancellare tutti gli spezzoni sponsorizzati nel lettore di YouTube."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Disattiva il Monitoraggio delle Sponsorizzazioni"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Disattiva il Monitoraggio delle Sponsorizzazioni"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Questa funzione tiene traccia di quali sponsorizzazioni hai saltato per far sapere agli utenti quanto è stato d'aiuto agli altri il loro contributo e\nviene utilizzato come metrica assieme ai voti positivi per filtrare lo spam dal database. L'estensione invia un messaggio\nal server ogni volta che salti una sponsorizzazione. Si spera che la maggior parte delle persone non modifichi questa impostazione così i numeri sono accurati. :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Mostra di Nuovo l'Avviso"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock è un'estensione che salta gli spezzoni con contenuti sponsorizzati nei video di YouTube. SponsorBlock è un'estensione crowdsourced per i browser che permette a chiunque di inviare i minutaggi degli spezzoni sponsorizzati nei video di YouTube. Quando una persona avrà inviato questa informazione, tutti gli utenti che utilizzano questa estensione potranno saltare lo spezzone sponsorizzato.",
|
||||
"description": "Full description of the extension on the store pages."
|
||||
},
|
||||
"website": {
|
||||
"message": "Sito Web",
|
||||
"description": "Used on Firefox Store Page"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Codice Sorgente",
|
||||
"description": "Used on Firefox Store Page"
|
||||
}
|
||||
}
|
||||
390
public/_locales/pl_PL/messages.json
Normal file
@@ -0,0 +1,390 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Nazwa rozszerzenia."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock na YouTube - Omiń reklamy sponsorów",
|
||||
"description": "Nazwa rozszerzenia."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Przewijaj reklamy sponsorów w filmach na YouTube. Zgłaszaj reklamy w nagraniach żeby nie marnować czasu innych.",
|
||||
"description": "Opis rozszerzenia."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Serwer odpowiedział, że to zapytanie jest niepoprawne"
|
||||
},
|
||||
"429": {
|
||||
"message": "Zgłosiłeś bardzo dużo segmentów reklamowych dla tego jednego nagrania, jesteś pewien, że jest ich tak dużo?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Treść została już wcześniej zgłoszona"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Kanał dodany do wyjątków!"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "sponsor"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "sponsorzy"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "segmet sponsorowany"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "segmenty sponsorowane"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Segment przewinięty"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Zgłoś"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Zgłoś ten segment reklamowy jako nieprawidłowy."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Odrzuć"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Ładowanie..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minuty"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Sekundy"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nigdy nie pokazuj"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Kliknij cofnij aby przenieść się do miejsca przed przewinięciem."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Cofnij"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Przewiń"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Zatrzymany"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "Żeby zmienić lub usunąć wartości, kliknij na guzik informacji lub otwórz okienko rozszerzenia klikając w ikonę rozszerzenia znajdującą się w prawym górnym rogu."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Jesteś pewien, że chcesz to usunąć?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Wystąpił błąd podczas przesyłania twojego zgłoszenia, proszę spróbować ponownie później."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Segmenty reklamowe dla tego nagrania są już w bazie!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Nie znaleziono segmentów reklamowych"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Reklama zaczyna się teraz"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Reklama kończy się teraz"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Nie znaleziono nagrania wideo w tej karcie. Jeśli wiesz, że to karta YouTube'a, zamknij to okienko i otwórz je ponownie. Jeśli to nie zadziała spróbuj przeładować stronę."
|
||||
},
|
||||
"success": {
|
||||
"message": "Sukces!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Zagłosowano!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Już na to głosowałeś."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Wygląda na to, że serwer nie działa. Skontaktuj się z dewloperem."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Błąd z połączeniem. Kod błędu: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Chcesz zgłosić segment sponsorowany dla nagrania z id"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Wygląda na to, że masz nie wysłane segmenty reklamowe. Cofnij się do tej strony i zgłoś je (nie zostały usunięte)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Wyczyść segmenty reklamowe"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Otwórz okienko SponsorBlock"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Zgłoś segmenty reklamowe"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Jesteś pewien, że chcesz to zgłosić?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Dodaj kanał do wyjątków"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Usuń kanał z listy wyjątków"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Głosuj na segment reklamowy"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Nagraj czasy segmentów reklamowych"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Jak na razie zgłosiłeś:"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Ocaliłeś ludzi przed "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Zobacz ranking użytkowników"
|
||||
},
|
||||
"here": {
|
||||
"message": "tutaj"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Kliknij guzik poniżej kiedy segment reklamowy się zaczyna i kończy żeby go oznaczyć i wysłać do bazy danych."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Podpowiedź: Klikając średnik kiedy zaznaczone jest zgłaszanie wideo możesz oznaczyć początek reklamy, znakiem cytatu oznaczysz jej koniec. (Klawisze można zmienić w opcjach)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Ostanie wybrane czasy reklam"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Usuń czasy"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Zgłoś czasy"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Ten dane są używane na naszej stronie żeby pokazać twój wkład. Zobacz to"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Ustaw nazwę użytkownika"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Dołącz do oficjalnego serwera na discordzie i podziel się wrażeniami i sugestiami!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Ukryj to"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Opcje"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Pokaż guziki w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Ukryj guziki w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Ta opcja ukrywa guziki zgłaszania reklamy w odtwarzaczu. Wiem, że mogą one irytować niektórych. Zamiast zgłaszania bezpośrednio w odtwarzaczu możesz to zrobić w tym okienku. Zawsze możesz zmienić te opcje później."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Pokaż guzik informacyjny w odtwarzaczu YouTube"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Ukryj guzik informacyjny w odtwarzaczu YouTube"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Jest to guzik otwierający popup na stronie YouTube."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Ukryj guzik usuwania w odtwarzaczu YouTube"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Pokaż guzik usuwania w odtwarzaczu YouTube"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Ten guzik pozwala ci wyczyścić wszystkie segmenty reklamowe w odtwarzaczu YouTube."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Wyłącz licznik przewinięć"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Włącz licznik przewinięć"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Ta opcja śledzi które segmenty pominąłeś i informuje zgłaszających ile czasu Ci zaoszczędzili, też wraz systemem głosowania pomaga wykrywać spam w zgłoszeniach. Rozszerzenie wysyła zapytanie do serwera za każdym razem kiedy przewinąłeś segment reklamowy. Miejmy nadzieję, że większość ludzi tego nie wyłączy i licznik wyświetleń będzie rzetelny. :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Pokaż informacje ponownie"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock jest rozszerzeniem które przewinie segmenty sponsorów w filmach na YouTube. SponsorBlock jest opartym na crowdsourcing rozszerzeniem które pozwala każdemu zgłaszać początek i koniec segmentu reklamowego w filmach na YouTube. Kiedy ktoś zgłosi taki fragment zostanie on pominięty przez innych użytkowników rozszerzenia.",
|
||||
"description": "Pełny opis rozszerzenia na stronie w sklepie."
|
||||
},
|
||||
"website": {
|
||||
"message": "Strona",
|
||||
"description": "Używane w sklepie Firefoxa"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Kod źródłowy",
|
||||
"description": "Używane w sklepie Firefoxa"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "Informacje zostały zaktualizowane!",
|
||||
"description": "Pierwsza linia po aktualizacji informacji."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Jeśli nadal jej nie lubisz wybierz opcje nie pokazuj więcej.",
|
||||
"description": "Druga linia po aktualizacji informacji."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Ustaw klawisz do oznaczania początku reklamy"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Ustaw klawisz do wysyłania czasów"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Wybierz klawisz klikając go na klawiaturze"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "Ustawiony klawisz to: "
|
||||
},
|
||||
"0": {
|
||||
"message": "Połączenie przerwane z powodu braku odpowiedzi. Sprawdź swoje połączenie z internetem. Jeśli wszystko z nim w porządku oznacza to, że serwer jest prawdopodobnie przeciążony lub nie działa."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Wyłącz SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Włącz SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Twój wkład",
|
||||
"description": "Nagłowek sekcji ze statystykami użytkownika."
|
||||
},
|
||||
"502": {
|
||||
"message": "Serwer jest prawdopodobnie przeciążony, spróbuj ponownie za kilka sekund."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Kod błędu: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Przewinąć reklamę?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Przewiń"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Wyłącz auto przewijanie"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Włącz auto przewijanie"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "Auto przewijanie przewinie segment za ciebie, wyłączone wyświetli komunikat z pytaniem czy chcesz przewinąć reklamę."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Przewinąłeś "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Oszczędziłeś sobie "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "minuta"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "minuty"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "godzina"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "godziny"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Oszczędziłeś ludziom"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " czasu."
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- Upewnij się, że zgłaszany fragment zawiera tylko reklamę i nic więcej.\n- Upewnij się, że nie zostanie przewinięta wartościowa treść\n- Jeśli całe nagranie to reklama, proszę nie zgłaszaj go. Blokowanie całych nagrań pojawi się wkrótce.\n- Nie ukrywaj treści które są istotne dla użytkownika (nie ukrywaj informacji, że recenzja produktu została opłacona przez producenta)"
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Wejdź na status.sponsor.ajay.app żeby sprawdzić czy serwer działa."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Zaimportuj/Wyeksportuj swój UserID"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Ta informacja jest poufna i działa jak hasło, użytkownik który ma do niej dostęp może zgłaszać treści jako ty."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Ustaw UserID"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Ostrzeżenie: Zmiana UserID jest nieodwracalna. Jesteś pewien, że chcesz to zrobić? Skopiuj obecny UserID na wszelki wypadek."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Stworzony przez"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Auto przewijanie"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Pokaż informację po przewiniętym fragmencie"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Jest obecnie ustawione jako:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Wesprzyj Invidious"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) to nieoficjalny klient YouTube. Aby go wesprzeć musisz przyznać dodatkowe uprawnienia rozszerzeniowi. Ta opcja nie działa w incognito i innych wersjach Chromium."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Wesprzyj Invidious, wyłącz auto przewijanie, ukryj guziki i więcej."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Dodaj instancje Invidious"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Dodaj niestandardową instancje Invidious. W formie domeny. Na przykład: invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Dodaj"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "Ta domena jest nieprawidłowa. Wartość powinna zawierać TYLKO domenę. Na przykład: invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Zresetuj listę instancji Invidious"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Zresetujesz listę instancji Invidious"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Obecne instancje:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Auto potwierdzanie"
|
||||
},
|
||||
"whatAutoUpvote": {
|
||||
"message": "To ustawienie sprawia, że wszystkie przewinięte przez ciebie a nie zgłoszone jako błąd segmenty reklamowe zostaną potwierdzone jako prawidłowe. Ta opcja nie działa jeśli okienko z informacją o przewinięciu jest ukryte."
|
||||
},
|
||||
"invidiousInfo1": {
|
||||
"message": "Invidious (nieoficjalny klient YouTube) została dodana do wspieranych!"
|
||||
},
|
||||
"invidiousInfo2": {
|
||||
"message": "Musisz odblokować to w opcjach aby móc to zrobić."
|
||||
}
|
||||
}
|
||||
244
public/_locales/pt_BR/messages.json
Normal file
@@ -0,0 +1,244 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Nome da extensão."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock para YouTube - Pule patrocínios",
|
||||
"description": "Nome da extensão."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Pule patrocinadores em vídeos do YouTube. Reporte patrocinadores em videos que você assiste para salvar o tempo dos outros.",
|
||||
"description": "Descrição da extensão."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "O servidor disse que esse pedido foi inválido"
|
||||
},
|
||||
"429": {
|
||||
"message": "Você enviou muitos segmentos para esse vídeo, tem certeza que tem tantos assim?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Isso já foi enviado antes"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Canal adicionado à lista branca!"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "patrocinador"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "patrocinadores"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "segmento de patrocinador"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "segmentos de patrocinadores"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Patrocinador pulado"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Reportar"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Reportar essa subimissão como inválida."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Ignorar"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Carregando..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minutos"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Segundos"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nunca mostrar"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Aperta reverter pulo para voltar onde estava"
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Reverter pulo"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Pular novamente"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Pausado"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "\n\nPara editar ou remover linhas individuais, clique com o botão direito ou abra o popup da extensão pelo icone no canto superior direito."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Tem certeza que quer limpar isso?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Teve um erro ao enviar seus segmentos, tente novamente depois."
|
||||
},
|
||||
|
||||
"sponsorFound": {
|
||||
"message": "Os patrocinadores desse vídeo estão no banco de dados!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Nenhum patrocinador encontrado"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Patrocínio começa agora"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Patrocínio termina agora"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Isso provavelmente não é uma tab do YouTube, ou você clicou muito cedo. \n Se sabe que é uma tab do YouTube,\n feche esse popup e abra de novo."
|
||||
},
|
||||
"success": {
|
||||
"message": "Sucesso!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Votado!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Você já votou antes."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Parece que o servidor caiu. Contate o desenvolvedor o quanto antes."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Um erro de conexão aconteceu: Código: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Quer enviar os segmentos para o vídeo de ID"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Parece que você se esqueceu de enviar alguns segmentos. Volta pra página para os enviar (não foram deletados)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Apagar intervalos dos patrocínios"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Abrir o Popup SponsorBlock"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Submeter intervalos dos patrocínios"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Tem a certeza que pretende submeter?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Meter canal na Whitelist"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Remover canal da Whitelist"
|
||||
},
|
||||
"whitelistDescription": {
|
||||
"message": "Colocar na Whitelist canais com patrocínios éticos que encoragem boas atitude, ou simplesmente canais com patrocínios engraçados. Ou não, é consigo."
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Vote num intervalo de patrocínio"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Registe um intervalo de patrocínio"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Até agora submeteu"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Poupaste a outros de "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Ver a leaderboard"
|
||||
},
|
||||
"here": {
|
||||
"message": "aqui"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Carregue neste botão abaixo quando o patrocínio começar e quando\n acabar para registar e submetê-lo à base de dados"
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Dica: Carregue na tecla ; enquanto num vídeo para registar o começo/fim de um patrocínio e \" para submeter"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Intervalos de Patrocínios Escolhidos mais Recentemente"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Limpar Intervalos"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Submeter Intervalos"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Isto é usado na página pública de estatísticas que mostra o quanto já contríbuíu. Veje-a"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Criar nomde de utilizador"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Junte-se ao discord oficial para sugerir dicas e sugestões!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Esconder isto"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Opções"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Mostrar botões no player do Youtube"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Esconder botões no player do Youtube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Isto esconde os botões que aparecem no player do Youtube para submeter patrocínios. Entendemos que possa ser\n incómodo a algumas pessoas. Em vez de usar esses botões pode usar os do popup. Para esconder a mensagem que aparece, \n ususe o botão na mesma que diz \"Don't show this again\". Pode sempre reactivar estas definições novamente."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Mostrar botão de Informações no player do Youtube"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Esconder botão de Informações no player do Youtube"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Este é o botão que abre o popup na pagina do Youtube."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Esconder botão de Apagar no player do Youtube"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Mostrar botão de Apagar no player do Youtube"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Este é o botão que lhe permite saltar todos os patrocínios do player do Youtube."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Desactivar registo de visualização de patrocínios"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Activar registo de visualização de patrocínios"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Esta funcionalidade regista que patrocínios tem saltado para que outros utilizadores saibam o quanto as suas submições têm ajudado outros\n e é usado como métrica de votos para evitar spam na base de dados. A extenção \n envia uma notificação ao servidor sempre que salta um patrocínio. Quanto menos pessoas desactivarem esta funcionalidade mais precisas serão as estimativas :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Mostrar notificação outra vez"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock é uma extensão que salta segmentos patrocinados em vídeos do YouTube. SponsorBlock é uma extenção crowdfunded que permite a qualquer um submeter o início e o fim de segmentos patrocinados. Assim que uma pessoa submete essa informação todos com a extenção poderam saltar automaticamete o patrocínio.",
|
||||
"description": "Descrição completa da extençao nas lojas dos browsers."
|
||||
},
|
||||
"website": {
|
||||
"message": "Site",
|
||||
"description": "Usado na pagina da loja do Firefox"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Código fonte",
|
||||
"description": "Usado na pagina da loja do Firefox"
|
||||
}
|
||||
}
|
||||
243
public/_locales/pt_pt/messages.json
Normal file
@@ -0,0 +1,243 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Nome da extensão."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock para o YouTube - Salte patrocínios",
|
||||
"description": "Nome da extensão."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Salte patrocinadores em vídeos do YouTube. Reporte patrocinadores em vídeos que assista para poupar tempo a outros.",
|
||||
"description": "Descrição da extensão."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "O servidor disse que este pedido foi inválido"
|
||||
},
|
||||
"429": {
|
||||
"message": "Enviou muitos segmentos para este vídeo, tem certeza que tem assim tantos?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Isso já foi enviado antes"
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Canal adicionado à whitelist!"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "patrocinador"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "patrocinadores"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "segmento de patrocínio"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "segmentos de patrocínio"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Patrocínio saltado"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Reportar"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Reportar subimissão como inválida."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Ignorar"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "A carregar..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "Minutos"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "Segundos"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Nunca mostrar"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Carregue em reverter salto para voltar a onde estava"
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Reverter salto"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Saltar novamente"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Pausado"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "\n\nPara editar ou remover linhas individuais, carregue com o botão direito ou abra o popup da extensão pelo icone no canto superior direito."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Tem certeza que deseja limpar isto?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "Erro ao enviar os seus segmentos, tente novamente mais tarde."
|
||||
},
|
||||
"sponsorFound": {
|
||||
"message": "Os patrocinadores desse vídeo estão no banco de dados!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Nenhum patrocinador encontrado"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Patrocínio começa agora"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Patrocínio termina agora"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Isto provavelmente não é uma tab do YouTube, ou pode ter clicado muito cedo. \n Se sabe que é uma tab do YouTube,\n feche este popup e abra de novo."
|
||||
},
|
||||
"success": {
|
||||
"message": "Sucesso!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Votado!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Já votou antes."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Parece que o servidor caiu. Contacte o desenvolvedor o quanto antes."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Deu-se um erro de conecção: Código: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Quer enviar os segmentos para o vídeo de ID"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Parece que se esqueceu de enviar alguns segmentos. Retorne à página para os enviar (não foram apagados)."
|
||||
},
|
||||
"clearTimes": {
|
||||
"message": "Apagar intervalos dos patrocínios"
|
||||
},
|
||||
"openPopup": {
|
||||
"message": "Abrir o Popup SponsorBlock"
|
||||
},
|
||||
"SubmitTimes": {
|
||||
"message": "Submeter intervalos dos patrocínios"
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Tem a certeza que pretende submeter?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Meter canal na Whitelist"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Remover canal da Whitelist"
|
||||
},
|
||||
"whitelistDescription": {
|
||||
"message": "Colocar na Whitelist canais com patrocínios éticos que encoragem boas atitude, ou simplesmente canais com patrocínios engraçados. Ou não, é consigo."
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Vote num intervalo de patrocínio"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Registe um intervalo de patrocínio"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "Até agora submeteu"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Poupaste a outros de "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Ver a leaderboard"
|
||||
},
|
||||
"here": {
|
||||
"message": "aqui"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Carregue neste botão abaixo quando o patrocínio começar e quando\n acabar para registar e submetê-lo à base de dados"
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Dica: Carregue na tecla ; enquanto num vídeo para registar o começo/fim de um patrocínio e \" para submeter"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Intervalos de Patrocínios Escolhidos mais Recentemente"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Limpar Intervalos"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Submeter Intervalos"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Isto é usado na página pública de estatísticas que mostra o quanto já contríbuíu. Veje-a"
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Criar nomde de utilizador"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Junte-se ao discord oficial para sugerir dicas e sugestões!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Esconder isto"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Opções"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Mostrar botões no player do Youtube"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Esconder botões no player do Youtube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Isto esconde os botões que aparecem no player do Youtube para submeter patrocínios. Entendemos que possa ser\n incómodo a algumas pessoas. Em vez de usar esses botões pode usar os do popup. Para esconder a mensagem que aparece, \n ususe o botão na mesma que diz \"Don't show this again\". Pode sempre reactivar estas definições novamente."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Mostrar botão de Informações no player do Youtube"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Esconder botão de Informações no player do Youtube"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Este é o botão que abre o popup na pagina do Youtube."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Esconder botão de Apagar no player do Youtube"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Mostrar botão de Apagar no player do Youtube"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Este é o botão que lhe permite saltar todos os patrocínios do player do Youtube."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Desactivar registo de visualização de patrocínios"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Activar registo de visualização de patrocínios"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Esta funcionalidade regista que patrocínios tem saltado para que outros utilizadores saibam o quanto as suas submições têm ajudado outros\n e é usado como métrica de votos para evitar spam na base de dados. A extenção \n envia uma notificação ao servidor sempre que salta um patrocínio. Quanto menos pessoas desactivarem esta funcionalidade mais precisas serão as estimativas :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Mostrar notificação outra vez"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock é uma extensão que salta segmentos patrocinados em vídeos do YouTube. SponsorBlock é uma extenção crowdfunded que permite a qualquer um submeter o início e o fim de segmentos patrocinados. Assim que uma pessoa submete essa informação todos com a extenção poderam saltar automaticamete o patrocínio.",
|
||||
"description": "Descrição completa da extençao nas lojas dos browsers."
|
||||
},
|
||||
"website": {
|
||||
"message": "Site",
|
||||
"description": "Usado na pagina da loja do Firefox"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Código fonte",
|
||||
"description": "Usado na pagina da loja do Firefox"
|
||||
}
|
||||
}
|
||||
421
public/_locales/ru/messages.json
Normal file
@@ -0,0 +1,421 @@
|
||||
{
|
||||
"Name": {
|
||||
"message": "SponsorBlock",
|
||||
"description": "Название расширения, не переводится."
|
||||
},
|
||||
"fullName": {
|
||||
"message": "SponsorBlock для YouTube - Пропускайте спонсорские вставки",
|
||||
"description": "Название расширения."
|
||||
},
|
||||
|
||||
"Description": {
|
||||
"message": "Пропускайте спонсорские вставки в видео на YouTube. Сообщайте о спонсорских вставках в видео, которые Вы смотрите, чтобы сэкономить время других пользователей.",
|
||||
"description": "Описание раширения."
|
||||
},
|
||||
"helpPage": {
|
||||
"message": "index_en.html"
|
||||
},
|
||||
"400": {
|
||||
"message": "Сервер отклонил этот запрос."
|
||||
},
|
||||
"429": {
|
||||
"message": "Вы отправили слишком много спонсоров для этого видео. Вы уверены, что их так много?"
|
||||
},
|
||||
"409": {
|
||||
"message": "Этот запрос был отправлен ранее."
|
||||
},
|
||||
"channelWhitelisted": {
|
||||
"message": "Канал добавлен в белый список!"
|
||||
},
|
||||
"Sponsor": {
|
||||
"message": "спонсора"
|
||||
},
|
||||
"Sponsors": {
|
||||
"message": "спонсоров"
|
||||
},
|
||||
"Segment": {
|
||||
"message": "спонсорская вставка"
|
||||
},
|
||||
"Segments": {
|
||||
"message": "спонсорские вставки"
|
||||
},
|
||||
"noticeTitle": {
|
||||
"message": "Спонсор пропущен"
|
||||
},
|
||||
"reportButtonTitle": {
|
||||
"message": "Ошибка"
|
||||
},
|
||||
"reportButtonInfo": {
|
||||
"message": "Сообщить, что информация об этом спонсорском сегменте ошибочна."
|
||||
},
|
||||
"Dismiss": {
|
||||
"message": "Закрыть"
|
||||
},
|
||||
"Loading": {
|
||||
"message": "Загрузка..."
|
||||
},
|
||||
"Mins": {
|
||||
"message": "мин"
|
||||
},
|
||||
"Secs": {
|
||||
"message": "сек"
|
||||
},
|
||||
"Hide": {
|
||||
"message": "Не показывать"
|
||||
},
|
||||
"hitGoBack": {
|
||||
"message": "Нажмите «Назад», чтобы вернуться обратно."
|
||||
},
|
||||
"unskip": {
|
||||
"message": "Назад"
|
||||
},
|
||||
"reskip": {
|
||||
"message": "Пропустить"
|
||||
},
|
||||
"paused": {
|
||||
"message": "Пауза"
|
||||
},
|
||||
"confirmMSG": {
|
||||
"message": "\n\nЧтобы изменить или удалить отдельные значения, нажмите кнопку «Информация» или откройте всплывающее окно расширения, щелкнув значок расширения в правом верхнем углу."
|
||||
},
|
||||
"clearThis": {
|
||||
"message": "Вы уверены, что хотите удалить эту информацию?\n\n"
|
||||
},
|
||||
"Unknown": {
|
||||
"message": "При отправке отчета о спонсорском сегменте произошла ошибка. Попытайтесь отправить его позже."
|
||||
},
|
||||
|
||||
"sponsorFound": {
|
||||
"message": "Спонсоры этого видео уже находятся в базе данных!"
|
||||
},
|
||||
"sponsor404": {
|
||||
"message": "Спонсорские вставки не найдены"
|
||||
},
|
||||
"sponsorStart": {
|
||||
"message": "Спонсорская вставка начинается сейчас"
|
||||
},
|
||||
"sponsorEnd": {
|
||||
"message": "Спонсорская вставка оканчивается сейчас"
|
||||
},
|
||||
"noVideoID": {
|
||||
"message": "Возможно, это не вкладка YouTube, или Вы нажали слишком рано. \n Если это вкладка YouTube,\n закройте это всплывающее окно и откройте его снова."
|
||||
},
|
||||
"success": {
|
||||
"message": "Успех!"
|
||||
},
|
||||
"voted": {
|
||||
"message": "Голос засчитан!"
|
||||
},
|
||||
"voteFail": {
|
||||
"message": "Вы уже проголосовали таким образом раньше."
|
||||
},
|
||||
"serverDown": {
|
||||
"message": "Кажется, сервер не работает. Свяжитесь с разработчиком."
|
||||
},
|
||||
"connectionError": {
|
||||
"message": "Ошибка соединения. Код ошибки: "
|
||||
},
|
||||
"wantToSubmit": {
|
||||
"message": "Вы точно хотите отправить отчёт о спонсорских вставках в видео с идентификатором"
|
||||
},
|
||||
"leftTimes": {
|
||||
"message": "Вы ещё не отправили отчёты о некоторых спонсорских вставках. Хотите вернуться на эту страницу, чтобы отправить их (они не удаляются)."
|
||||
},
|
||||
"submitCheck": {
|
||||
"message": "Вы уверены, что хотите отправить эту информацию?"
|
||||
},
|
||||
"whitelistChannel": {
|
||||
"message": "Добавить канал в белый список"
|
||||
},
|
||||
"removeFromWhitelist": {
|
||||
"message": "Удалить канал из белого списка"
|
||||
},
|
||||
"voteOnTime": {
|
||||
"message": "Проголосовать за время спонсорской вставки"
|
||||
},
|
||||
"recordTimes": {
|
||||
"message": "Записать время спонсорской вставки"
|
||||
},
|
||||
"soFarUHSubmited": {
|
||||
"message": "На данный момент Вы отправили"
|
||||
},
|
||||
"savedPeopleFrom": {
|
||||
"message": "Вы помогли людям сэкономить "
|
||||
},
|
||||
"viewLeaderboard": {
|
||||
"message": "Посмотреть доску почёта"
|
||||
},
|
||||
"here": {
|
||||
"message": "здесь"
|
||||
},
|
||||
"recordTimesDescription": {
|
||||
"message": "Нажмите кнопку ниже, когда спонсорская вставка начинается и заканчивается, чтобы записать\nи отправить её в базу данных."
|
||||
},
|
||||
"popupHint": {
|
||||
"message": "Подсказка: нажмите ;, чтобы сообщить начало/конец спонсорской вставки, и \", чтобы отправить. (Это можно изменить в настройках)"
|
||||
},
|
||||
"lastTimes": {
|
||||
"message": "Последнее выбранное время спонсорской вставки"
|
||||
},
|
||||
"clearTimesButton": {
|
||||
"message": "Очистить время"
|
||||
},
|
||||
"submitTimesButton": {
|
||||
"message": "Отправить время"
|
||||
},
|
||||
"publicStats": {
|
||||
"message": "Оно используется на публичной странице статистики, чтобы показать Ваш вклад. Её можно посмотреть "
|
||||
},
|
||||
"setUsername": {
|
||||
"message": "Установить имя пользователя"
|
||||
},
|
||||
"discordAdvert": {
|
||||
"message": "Присоединяйтесь к официальному серверу Discord, чтобы оставить предложения и обратную связь!"
|
||||
},
|
||||
"hideThis": {
|
||||
"message": "Скрыть это"
|
||||
},
|
||||
"Options": {
|
||||
"message": "Настройки"
|
||||
},
|
||||
"showButtons": {
|
||||
"message": "Показывать кнопки в плеере YouTube"
|
||||
},
|
||||
"hideButtons": {
|
||||
"message": "Скрыть кнопки в плеере YouTube"
|
||||
},
|
||||
"hideButtonsDescription": {
|
||||
"message": "Эта настройка скрывает кнопки для отправки спонсорских вставок, которые появляются в плеере YouTube. Они могут раздражать\n некоторых. Вместо кнопок для отправки спонсорских вставок можно использовать это всплывающее окно. Чтобы скрыть\nуведомление, нажмите кнопку \"Не показывать снова\" в уведомлении. Вы всегда сможете включить эти настройки обратно."
|
||||
},
|
||||
"showInfoButton": {
|
||||
"message": "Показывать кнопку информации в плеере YouTube"
|
||||
},
|
||||
"hideInfoButton": {
|
||||
"message": "Скрыть кнопку информации в плеере YouTube"
|
||||
},
|
||||
"whatInfoButton": {
|
||||
"message": "Эта кнопка открывает всплывающее окно на странице YouTube."
|
||||
},
|
||||
"hideDeleteButton": {
|
||||
"message": "Скрыть кнопку удаления в плеере YouTube"
|
||||
},
|
||||
"showDeleteButton": {
|
||||
"message": "Показывать кнопку удаления в плеере YouTube"
|
||||
},
|
||||
"whatDeleteButton": {
|
||||
"message": "Эта кнопка позволяет Вам очистить все спонсорские вставки в плеере YouTube."
|
||||
},
|
||||
"disableViewTracking": {
|
||||
"message": "Отключить отслеживание количества пропусков спонсорских вставок"
|
||||
},
|
||||
"enableViewTracking": {
|
||||
"message": "Включить отслеживание количества пропусков спонсорских вставок"
|
||||
},
|
||||
"whatViewTracking": {
|
||||
"message": "Эта возможность отслеживает, какие спонсорские вставки Вы пропустили, чтобы помочь пользователям узнать, насколько их\nвклад помог другим, и используется как метрика, чтобы убедиться, что спам не попадает в базу данных. Расширение отправляет\nсообщение на сервер каждый раз, когда Вы пропускаете спонсорскую вставку. Надеемся, большая часть пользователей не поменяет эту настройку, так что у нас будет точная статистика просмотров :)"
|
||||
},
|
||||
"showNotice": {
|
||||
"message": "Показывать уведомление снова"
|
||||
},
|
||||
"longDescription": {
|
||||
"message": "SponsorBlock — это расширение, которое пропускает спонсорские вставки в видео на YouTube. SponsorBlock — это краудсорсинговое расширение, которое позволяет каждому отправить время начала и конца спонсорских сегментов в видео на YouTube. После того, как кто-нибудь отправляет эту информацию, все остальные пользователи расширения будут автоматически пропускать спонсорские сегменты.",
|
||||
"description": "Полное описание расширения на страницах магазинов."
|
||||
},
|
||||
"website": {
|
||||
"message": "Сайт",
|
||||
"description": "Используется на странице магазина Firefox"
|
||||
},
|
||||
"sourceCode": {
|
||||
"message": "Исходный код",
|
||||
"description": "Используется на странице магазина Firefox"
|
||||
},
|
||||
"noticeUpdate": {
|
||||
"message": "Уведомление было обновлено!",
|
||||
"description": "The first line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"noticeUpdate2": {
|
||||
"message": "Если оно Вам всё равно не нравится, нажмите \"не показывать\".",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Назначить горячую клавишу для начала спонсорской вставки"
|
||||
},
|
||||
"setSubmitKeybind": {
|
||||
"message": "Назначить горячую клавишу для отправки"
|
||||
},
|
||||
"keybindDescription": {
|
||||
"message": "Нажмите клавишу, чтобы выбрать её"
|
||||
},
|
||||
"keybindDescriptionComplete": {
|
||||
"message": "Клавиша назначена на: "
|
||||
},
|
||||
"0": {
|
||||
"message": "Таймаут подключения. Проверьте ваше соединение с интернетом. Если ваш интернет работает, сервер, скорее всего, перегружен или лежит."
|
||||
},
|
||||
"disableSkipping": {
|
||||
"message": "Отключить SponsorBlock"
|
||||
},
|
||||
"enableSkipping": {
|
||||
"message": "Включить SponsorBlock"
|
||||
},
|
||||
"yourWork": {
|
||||
"message": "Ваша работа",
|
||||
"description": "Used to describe the section that will show you the statistics from your submissions."
|
||||
},
|
||||
"502": {
|
||||
"message": "Похоже, сервер перегружен. Попробуйте ещё раз через несколько секунд."
|
||||
},
|
||||
"errorCode": {
|
||||
"message": "Код ошибки: "
|
||||
},
|
||||
"noticeTitleNotSkipped": {
|
||||
"message": "Пропустить спонсорскую вставку?"
|
||||
},
|
||||
"skip": {
|
||||
"message": "Пропустить"
|
||||
},
|
||||
"disableAutoSkip": {
|
||||
"message": "Отключить автоматический пропуск"
|
||||
},
|
||||
"enableAutoSkip": {
|
||||
"message": "Включить автоматический пропуск"
|
||||
},
|
||||
"autoSkipDescription": {
|
||||
"message": "Автоматический пропуск будет пропускать спонсорские вставки за Вас. Если выключено, будет показываться уведомление с предложением пропустить."
|
||||
},
|
||||
"youHaveSkipped": {
|
||||
"message": "Вы пропустили "
|
||||
},
|
||||
"youHaveSaved": {
|
||||
"message": "Вы сэкономили "
|
||||
},
|
||||
"minLower": {
|
||||
"message": "минуту"
|
||||
},
|
||||
"minsLower": {
|
||||
"message": "минут"
|
||||
},
|
||||
"hourLower": {
|
||||
"message": "час"
|
||||
},
|
||||
"hoursLower": {
|
||||
"message": "часов"
|
||||
},
|
||||
"youHaveSavedTime": {
|
||||
"message": "Вы сэкономили людям"
|
||||
},
|
||||
"youHaveSavedTimeEnd": {
|
||||
"message": " их жизней."
|
||||
},
|
||||
"guildlinesSummary": {
|
||||
"message": "- Убедитесь, что Ваш сегмент содержит только платную интеграцию, и больше ничего.\n- Убедитесь, что пропуск этого сегмента не пропустит никакой ценный контент\n- Если всё видео целиком спонсорское, пожалуйста, не сообщайте о нём. Система для сообщения о целых видео скоро выйдет.\n- Пожалуйста, не сообщайте об отказах от ответственности, которые могут показать предвзятость (если видео с обзором проплачено, не пропускайте, когда они это упоминают)."
|
||||
},
|
||||
"statusReminder": {
|
||||
"message": "Смотрите состояние сервера на status.sponsor.ajay.app."
|
||||
},
|
||||
"changeUserID": {
|
||||
"message": "Импортировать/экспортировать Ваш идентификатор пользователя"
|
||||
},
|
||||
"whatChangeUserID": {
|
||||
"message": "Это нужно держать в секрете. Это как пароль, не стоит им ни с кем делиться. Если он у кого-то есть, он сможет выдать себя за Вас."
|
||||
},
|
||||
"setUserID": {
|
||||
"message": "Установить идентификатор пользователя"
|
||||
},
|
||||
"userIDChangeWarning": {
|
||||
"message": "Внимание: изменение идентификатора пользователя необратимо. Вы действительно хотите это сделать? Сделайте резервную копию вашего старого на всякий случай."
|
||||
},
|
||||
"createdBy": {
|
||||
"message": "Создано"
|
||||
},
|
||||
"autoSkip": {
|
||||
"message": "Автоматический пропуск"
|
||||
},
|
||||
"showSkipNotice": {
|
||||
"message": "Показывать уведомление после пропуска спонсорской вставки"
|
||||
},
|
||||
"keybindCurrentlySet": {
|
||||
"message": ". Он сейчас назначен на:"
|
||||
},
|
||||
"supportInvidious": {
|
||||
"message": "Поддержка Invidious"
|
||||
},
|
||||
"supportInvidiousDescription": {
|
||||
"message": "Invidious (invidio.us) — это неофициальный клиент YouTube. Чтобы включить поддержку, Вам понадобится принять дополнительные разрешения. Это НЕ работает в приватном режиме в Chrome и других вариантах Chromium."
|
||||
},
|
||||
"optionsInfo": {
|
||||
"message": "Включить поддержку Invidious, выключить автоматический пропуск, скрыть кнопки и не только."
|
||||
},
|
||||
"addInvidiousInstance": {
|
||||
"message": "Добавить инстанс Invidious"
|
||||
},
|
||||
"addInvidiousInstanceDescription": {
|
||||
"message": "Добавить свой инстанс Invidious. Формат: ТОЛЬКО домен. Например, invidious.ajay.app"
|
||||
},
|
||||
"add": {
|
||||
"message": "Добавить"
|
||||
},
|
||||
"addInvidiousInstanceError": {
|
||||
"message": "Это неправильный домен. Введите ТОЛЬКО домен. Например, invidious.ajay.app"
|
||||
},
|
||||
"resetInvidiousInstance": {
|
||||
"message": "Сбросить список инстансов Invidious"
|
||||
},
|
||||
"resetInvidiousInstanceAlert": {
|
||||
"message": "Вы собираетесь сбросить список инстансов Invidious"
|
||||
},
|
||||
"currentInstances": {
|
||||
"message": "Текущие инстансы:"
|
||||
},
|
||||
"enableAutoUpvote": {
|
||||
"message": "Автоматически голосовать \"за\""
|
||||
},
|
||||
"whatAutoUpvote": {
|
||||
"message": "Если это включено, расширение будет голосовать \"за\" все предложения других пользователей, если Вы на них не пожалуетесь. Если уведомление отключено, это не будет происходить."
|
||||
},
|
||||
"minDuration": {
|
||||
"message": "Минимальная длительность (секунд):"
|
||||
},
|
||||
"minDurationDescription": {
|
||||
"message": "Спонсорские сегменты короче этого значения не будут пропускаться и не будут показаны в плеере."
|
||||
},
|
||||
"shortCheck": {
|
||||
"message": "Следующий диапазон времени короче, чем Ваша настройка минимальной длительности. Это может означать, что он уже был отправлен, и просто игнорируется из-за этой настройки. Вы действительно хотите отправить?"
|
||||
},
|
||||
"showUploadButton": {
|
||||
"message": "Показывать кнопку отправки"
|
||||
},
|
||||
"whatUploadButton": {
|
||||
"message": "Эта кнопка появляется в плеере YouTube после того, как Вы выбрали отметку времени и готовы к отправке."
|
||||
},
|
||||
"customServerAddress": {
|
||||
"message": "Адрес сервера SponsorBlock"
|
||||
},
|
||||
"customServerAddressDescription": {
|
||||
"message": "Адрес, по которому SponsorBlock обращается к серверу.\nМеняйте только если Вы подняли свой сервер."
|
||||
},
|
||||
"save": {
|
||||
"message": "Сохранить"
|
||||
},
|
||||
"reset": {
|
||||
"message": "Сбросить"
|
||||
},
|
||||
"customAddressError": {
|
||||
"message": "Этот адрес неправильного формата. Убедитесь, что он начинается с http:// или https://, и что на конце нет слэшей."
|
||||
},
|
||||
"areYouSureReset": {
|
||||
"message": "Вы действительно хотите это сбросить?"
|
||||
},
|
||||
"confirmPrivacy": {
|
||||
"message": "Было обнаружено, что это видео непубличное. Нажмите \"отмена\", если не хотите проверять его на спонсоров."
|
||||
},
|
||||
"unlistedCheck": {
|
||||
"message": "Игнорировать непубличные видео"
|
||||
},
|
||||
"whatUnlistedCheck": {
|
||||
"message": "Эта настройка значительно замедлит SponsorBlock. Поиск спонсоров требует отправки идентификатора видео на сервер. Если Вас беспокоит отправка идентификаторов непубличных видео по интернету, включите эту настройку."
|
||||
},
|
||||
"mobileUpdateInfo": {
|
||||
"message": "m.youtube.com теперь поддерживается"
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@
|
||||
}
|
||||
|
||||
.sponsorSkipNotice {
|
||||
min-width: 280px;
|
||||
min-width: 350px;
|
||||
background-color: rgba(28, 28, 28, 0.9);
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
@@ -1,5 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
<title> SponsorBlock </title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<link href="styles.css" rel="stylesheet"/>
|
||||
</head>
|
||||
@@ -7,16 +10,16 @@
|
||||
<body>
|
||||
|
||||
<div id="title">
|
||||
<img src="https://github.com/ajayyy/SponsorBlock/raw/master/icons/LogoSponsorBlocker256px.png" height="80" class="profilepic"/>
|
||||
<img src="../icons/LogoSponsorBlocker256px.png" height="80" class="profilepic"/>
|
||||
SponsorBlock
|
||||
</div>
|
||||
|
||||
<center>
|
||||
<div class="container">
|
||||
|
||||
<p class="createdBy">Created By <a href="https://ajay.app">Ajay Ramachandran</a></p>
|
||||
<p class="createdBy">Created By <a href="https://ajay.app">Ajay Ramachandran</a> <img src="https://ajay.app/newprofilepic.jpg" height="30" class="profilepiccircle"/></p>
|
||||
|
||||
<p>
|
||||
Thanks for installing SponsorBlock. Here are some quick tips for getting started. Please join the Discord if you have any questions or suggestions.
|
||||
Thanks for installing SponsorBlock. Here are some quick tips for getting started. Feel free to contact me if you have any questions.
|
||||
</p>
|
||||
|
||||
<p class="projectPreview">
|
||||
@@ -27,6 +30,15 @@
|
||||
Come contribute, make some suggestions and help out in the Discord: <a href="https://discord.gg/QnmVMpU">https://discord.gg/QnmVMpU</a>
|
||||
</p>
|
||||
|
||||
<div class="center">
|
||||
<a class="bigText" href="/options/options.html">Enable optional features</a>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Some features, such as support for non third-party YouTube sites, are disabled by default and can be enabled in the options. These can be enabled or disabled at any time.
|
||||
You can also hide/show all UI elements added to the YouTube page.
|
||||
</p>
|
||||
|
||||
<h1>How skipping works</h1>
|
||||
|
||||
<p class="projectPreview">
|
||||
@@ -39,10 +51,10 @@
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
Whenever you skip a video, you will get a notice report that submission. If the timing seems wrong, report it! You can also vote in the popup. The extension auto upvotes it if you don't report it, so make sure to report when necessary.
|
||||
Whenever you skip a video, you will get a notice report that submission. If the timing seems wrong, report it! You can also vote in the popup. The extension auto upvotes it if you don't report it, so make sure to report when necessary (this can be disabled in the options).
|
||||
</p>
|
||||
|
||||
<center><img height="120px" src="https://user-images.githubusercontent.com/12688112/63067735-5a638700-bede-11e9-8147-f321b57527ec.gif"></center>
|
||||
<div class="center"><img height="120px" src="https://user-images.githubusercontent.com/12688112/63067735-5a638700-bede-11e9-8147-f321b57527ec.gif"></div>
|
||||
|
||||
<h1>Submitting</h1>
|
||||
|
||||
@@ -74,6 +86,7 @@
|
||||
|
||||
<p>
|
||||
There are hotkeys if you want to use them. You must be focused on the YouTube player to use them. Press the semicolon key to indicate the start/end of a sponsor segment and click the appostrophe to submit.
|
||||
These can be changed in the options. If you don't use QWERTY, you should probably change the keybinds.
|
||||
</p>
|
||||
|
||||
<h1>I hate these buttons, they are so ugly</h1>
|
||||
@@ -100,7 +113,7 @@
|
||||
Ask on Discord or make an Issue on GitHub. I am happy to hear suggestions or improvements you want. You may also contribute code or graphics if you would like.
|
||||
</p>
|
||||
|
||||
<h1>Where can I get the source code</h1>
|
||||
<h1>Where can I get the source code?</h1>
|
||||
|
||||
<h4 style="display: inline">Client:</h4>
|
||||
<!-- Github logo -->
|
||||
@@ -110,7 +123,7 @@
|
||||
<!-- Github logo -->
|
||||
<a href="https://github.com/ajayyy/SponsorBlockServer"><svg aria-hidden="true" version="1.1" viewBox="0 0 16 16" height="58px" style="padding-left: 15px"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path></svg></a>
|
||||
|
||||
<h1>Credit</h1>
|
||||
<h1>Credits</h1>
|
||||
|
||||
<p>The awesome <a href="https://github.com/omarroth/invidious/wiki/API">Invidious API</a> is used to grab the time the video was published.</p>
|
||||
|
||||
@@ -118,6 +131,6 @@
|
||||
|
||||
<p>Some icons made by <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> and are licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></p>
|
||||
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
@@ -1,5 +1,19 @@
|
||||
:not(.hljs-keyword):not(.hljs-comment):not(.hljs-number):not(.hljs-string):not(pre):not(code) {
|
||||
.bigText {
|
||||
font-size: 50px;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #333333;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 60%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.projectPreview {
|
||||
@@ -8,24 +22,24 @@
|
||||
|
||||
.projectPreviewImage {
|
||||
position: absolute;
|
||||
left: -90;
|
||||
width: 80;
|
||||
left: -90px;
|
||||
width: 80px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.projectPreviewImageLarge {
|
||||
position: absolute;
|
||||
left: -210;
|
||||
width: 200;
|
||||
left: -210px;
|
||||
width: 200px;
|
||||
top: 50%;
|
||||
transform: translateY(-20%);
|
||||
}
|
||||
|
||||
.projectPreviewImageLargeRight {
|
||||
position: absolute;
|
||||
right: -210;
|
||||
width: 200;
|
||||
right: -210px;
|
||||
width: 200px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
@@ -43,37 +57,27 @@
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
|
||||
font-family: sans-serif;
|
||||
font-size: 50;
|
||||
font-size: 50px;
|
||||
color: #212121;
|
||||
|
||||
/* height: 100; */
|
||||
|
||||
padding: 20;
|
||||
padding: 20px;
|
||||
|
||||
text-decoration: none;
|
||||
|
||||
transition: font-size 1s;
|
||||
}
|
||||
|
||||
#title:hover {
|
||||
font-size: 60;
|
||||
|
||||
transition: font-size 1s;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-family: sans-serif;
|
||||
font-size: 40;
|
||||
font-size: 40px;
|
||||
color: #dad8d8;
|
||||
|
||||
padding-top: 10;
|
||||
padding-top: 10px;
|
||||
|
||||
transition: font-size 0.4s;
|
||||
}
|
||||
|
||||
.subtitle:hover {
|
||||
font-size: 45;
|
||||
font-size: 45px;
|
||||
|
||||
transition: font-size 0.4s;
|
||||
}
|
||||
@@ -83,13 +87,19 @@
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.profilepiccircle {
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.link {
|
||||
padding: 20;
|
||||
padding: 20px;
|
||||
|
||||
height: 80px;
|
||||
|
||||
@@ -103,29 +113,24 @@ a {
|
||||
}
|
||||
|
||||
#contact,.smalllink {
|
||||
font-family: sans-serif;
|
||||
font-size: 25;
|
||||
font-size: 25px;
|
||||
color: #e8e8e8;
|
||||
|
||||
text-align: center;
|
||||
|
||||
padding: 10;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#contact {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
p,li {
|
||||
font-family: sans-serif;
|
||||
font-size: 20;
|
||||
p,li,a {
|
||||
font-size: 20px;
|
||||
color: #c4c4c4;
|
||||
|
||||
padding: 10;
|
||||
}
|
||||
|
||||
p,li,code,a {
|
||||
max-width: 60%;
|
||||
text-align: left;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
@@ -137,7 +142,7 @@ p,li,code,a {
|
||||
|
||||
.projectPreviewImage {
|
||||
position: unset;
|
||||
width: 130;
|
||||
width: 130px;
|
||||
display: block;
|
||||
margin: auto;
|
||||
transform: none;
|
||||
@@ -155,20 +160,18 @@ img {
|
||||
}
|
||||
|
||||
#recentPostTitle {
|
||||
font-family: sans-serif;
|
||||
font-size: 30;
|
||||
font-size: 30px;
|
||||
color: #dad8d8;
|
||||
}
|
||||
|
||||
#recentPostDate {
|
||||
font-family: sans-serif;
|
||||
font-size: 15;
|
||||
font-size: 15px;
|
||||
color: #dad8d8;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
font-family: sans-serif;
|
||||
color: #dad8d8;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
svg {
|
||||
|
Before Width: | Height: | Size: 551 B After Width: | Height: | Size: 551 B |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
BIN
public/icons/newprofilepic.jpg
Normal file
|
After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
326
public/options/options.css
Normal file
@@ -0,0 +1,326 @@
|
||||
/* Options page CSS */
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.keybind-status {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.small-description {
|
||||
color: white;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.medium-description {
|
||||
color: white;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.option-text-box {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.option-button {
|
||||
cursor: pointer;
|
||||
|
||||
background-color: #c00000;
|
||||
padding: 10px;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.option-button:hover {
|
||||
background-color: #fc0303;
|
||||
}
|
||||
|
||||
.option-button.disabled {
|
||||
cursor: default;
|
||||
|
||||
background-color: #520000;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
#options {
|
||||
max-width: 60%;
|
||||
text-align: left;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.switch-container:after {
|
||||
content: attr(label-name);
|
||||
position: absolute;
|
||||
padding: 4px;
|
||||
width: max-content;
|
||||
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.text-label-container {
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.switch input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #707070;
|
||||
}
|
||||
|
||||
.animated * {
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.animated .slider:before {
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: #fc0303;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(16px);
|
||||
-ms-transform: translateX(16px);
|
||||
transform: translateX(16px);
|
||||
}
|
||||
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
|
||||
/* Boilerplate CSS from https://ajay.app */
|
||||
|
||||
body {
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
.projectPreview {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.projectPreviewImage {
|
||||
position: absolute;
|
||||
left: -90px;
|
||||
width: 80px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.projectPreviewImageLarge {
|
||||
position: absolute;
|
||||
left: -210px;
|
||||
width: 200px;
|
||||
top: 50%;
|
||||
transform: translateY(-20%);
|
||||
}
|
||||
|
||||
.projectPreviewImageLargeRight {
|
||||
position: absolute;
|
||||
right: -210px;
|
||||
width: 200px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.createdBy {
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#title {
|
||||
background-color: #636363;
|
||||
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
|
||||
font-size: 50px;
|
||||
color: #212121;
|
||||
|
||||
padding: 20px;
|
||||
|
||||
text-decoration: none;
|
||||
|
||||
transition: font-size 1s;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 40px;
|
||||
color: #dad8d8;
|
||||
|
||||
padding-top: 10px;
|
||||
|
||||
transition: font-size 0.4s;
|
||||
}
|
||||
|
||||
.subtitle:hover {
|
||||
font-size: 45px;
|
||||
|
||||
transition: font-size 0.4s;
|
||||
}
|
||||
|
||||
.profilepic {
|
||||
background-color: #636363 !important;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.profilepiccircle {
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.link {
|
||||
padding: 20px;
|
||||
|
||||
height: 80px;
|
||||
|
||||
transition: height 0.2s;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
height: 95px;
|
||||
|
||||
transition: height 0.2s;
|
||||
}
|
||||
|
||||
#contact,.smalllink {
|
||||
font-size: 25px;
|
||||
color: #e8e8e8;
|
||||
|
||||
text-align: center;
|
||||
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#contact {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
p,li {
|
||||
font-size: 20px;
|
||||
color: #c4c4c4;
|
||||
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
p,li,code,a {
|
||||
max-width: 60%;
|
||||
text-align: left;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
@media screen and (orientation:portrait) {
|
||||
p,li,code,a {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.projectPreviewImage {
|
||||
position: unset;
|
||||
width: 130px;
|
||||
display: block;
|
||||
margin: auto;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
.previewImage {
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#recentPostTitle {
|
||||
font-size: 30px;
|
||||
color: #dad8d8;
|
||||
}
|
||||
|
||||
#recentPostDate {
|
||||
font-size: 15px;
|
||||
color: #dad8d8;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
color: #dad8d8;
|
||||
}
|
||||
|
||||
svg {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.number-container:before {
|
||||
content: attr(label-name);
|
||||
padding-right: 4px;
|
||||
width: max-content;
|
||||
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
}
|
||||
361
public/options/options.html
Normal file
@@ -0,0 +1,361 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
<title>Options - SponsorBlock</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<link href="options.css" rel="stylesheet"/>
|
||||
|
||||
<script src="../js/vendor.js"></script>
|
||||
<script src="../js/options.js"></script>
|
||||
</head>
|
||||
|
||||
<body class="sponsorBlockPageBody">
|
||||
|
||||
<div id="title">
|
||||
<img src="../icons/LogoSponsorBlocker256px.png" height="80" class="profilepic"/>
|
||||
SponsorBlock
|
||||
</div>
|
||||
|
||||
<div class="center">
|
||||
<p class="createdBy">__MSG_createdBy__ <a href="https://ajay.app">Ajay Ramachandran</a> <img src="../icons/newprofilepic.jpg" height="30" class="profilepiccircle"/></p>
|
||||
|
||||
<h1>__MSG_Options__</h1>
|
||||
|
||||
<div id="options" class="hidden">
|
||||
|
||||
<div id="support-invidious" option-type="toggle" sync-option="supportInvidious">
|
||||
<label class="switch-container" label-name="__MSG_supportInvidious__">
|
||||
<label class="switch">
|
||||
<input type="checkbox">
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_supportInvidiousDescription__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="private-text-change" sync-option="invidiousInstances">
|
||||
<div class="option-button trigger-button">
|
||||
__MSG_addInvidiousInstance__
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_addInvidiousInstanceDescription__</div>
|
||||
|
||||
<div class="option-hidden-section hidden">
|
||||
<br/>
|
||||
|
||||
<input class="option-text-box" type="text">
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="option-button text-change-set inline">
|
||||
__MSG_add__
|
||||
</div>
|
||||
|
||||
<div class="option-button invidious-instance-reset inline">
|
||||
__MSG_resetInvidiousInstance__
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<span class="small-description">__MSG_currentInstances__</span>
|
||||
<span class="small-description" option-type="display" sync-option="invidiousInstances"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" toggle-type="reverse" sync-option="disableAutoSkip">
|
||||
<label class="switch-container" label-name="__MSG_autoSkip__">
|
||||
<label class="switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_autoSkipDescription__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
<div option-type="keybind-change" sync-option="startSponsorKeybind">
|
||||
<div class="option-button trigger-button">
|
||||
__MSG_setStartSponsorShortcut__
|
||||
</div>
|
||||
|
||||
<div class="option-hidden-section hidden">
|
||||
<br/>
|
||||
|
||||
<div class="medium-description keybind-status">
|
||||
__MSG_keybindDescription__
|
||||
</div>
|
||||
|
||||
<span class="medium-description bold keybind-status-key">
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="keybind-change" sync-option="submitKeybind">
|
||||
<div class="option-button trigger-button">
|
||||
__MSG_setSubmitKeybind__
|
||||
</div>
|
||||
|
||||
<div class="option-hidden-section hidden">
|
||||
<br/>
|
||||
|
||||
<div class="medium-description keybind-status">
|
||||
__MSG_keybindDescription__
|
||||
</div>
|
||||
|
||||
<span class="medium-description bold keybind-status-key">
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="number-change" sync-option="minDuration">
|
||||
<label class="number-container" label-name="__MSG_minDuration__">
|
||||
<input type="number" step="0.1" min="0">
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_minDurationDescription__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" toggle-type="reverse" sync-option="dontShowNotice">
|
||||
<label class="switch-container" label-name="__MSG_showSkipNotice__">
|
||||
<label class="switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" toggle-type="reverse" sync-option="hideVideoPlayerControls">
|
||||
<label class="switch-container" label-name="__MSG_showButtons__">
|
||||
<label class="switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_hideButtonsDescription__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" toggle-type="reverse" sync-option="hideInfoButtonPlayerControls">
|
||||
<label class="switch-container" label-name="__MSG_showInfoButton__">
|
||||
<label class="switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_whatInfoButton__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" toggle-type="reverse" sync-option="hideDeleteButtonPlayerControls">
|
||||
<label class="switch-container" label-name="__MSG_showDeleteButton__">
|
||||
<label class="switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_whatDeleteButton__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" toggle-type="reverse" sync-option="hideUploadButtonPlayerControls">
|
||||
<label class="switch-container" label-name="__MSG_showUploadButton__">
|
||||
<label class="switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_whatUploadButton__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" sync-option="autoUpvote">
|
||||
<label class="switch-container" label-name="__MSG_enableAutoUpvote__">
|
||||
<label class="switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_whatAutoUpvote__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" sync-option="trackViewCount">
|
||||
<label class="switch-container" label-name="__MSG_enableViewTracking__">
|
||||
<label class="switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_whatViewTracking__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="toggle" sync-option="checkForUnlistedVideos">
|
||||
<label class="switch-container" label-name="__MSG_unlistedCheck__">
|
||||
<label class="switch">
|
||||
<input type="checkbox">
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_whatUnlistedCheck__</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="private-text-change" sync-option="userID" confirm-message="userIDChangeWarning">
|
||||
<div class="option-button trigger-button">
|
||||
__MSG_changeUserID__
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_whatChangeUserID__</div>
|
||||
|
||||
<div class="option-hidden-section hidden">
|
||||
<br/>
|
||||
|
||||
<input class="option-text-box" type="text">
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="option-button text-change-set">
|
||||
__MSG_setUserID__
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="private-text-change" sync-option="*" confirm-message="exportOptionsWarning">
|
||||
<div class="option-button trigger-button">
|
||||
__MSG_exportOptions__
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_whatExportOptions__</div>
|
||||
|
||||
<div class="option-hidden-section hidden">
|
||||
<br/>
|
||||
|
||||
<input class="option-text-box" type="text">
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="option-button text-change-set">
|
||||
__MSG_setOptions__
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="text-change" sync-option="serverAddress">
|
||||
<label class="text-label-container">
|
||||
<div>__MSG_customServerAddress__</div>
|
||||
|
||||
<input class="option-text-box" type="text">
|
||||
</label>
|
||||
|
||||
<div class="option-button text-change-set inline">
|
||||
__MSG_save__
|
||||
</div>
|
||||
|
||||
<div class="option-button text-change-reset inline">
|
||||
__MSG_reset__
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="small-description">__MSG_customServerAddressDescription__</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
@@ -35,6 +35,10 @@ sub.popupElement {
|
||||
}
|
||||
/* end reset */
|
||||
|
||||
#sponsorBlockPopupLogo {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.popupElement {
|
||||
font-family: 'Source Sans Pro', sans-serif;
|
||||
|
||||
@@ -43,12 +47,13 @@ sub.popupElement {
|
||||
|
||||
h1.popupElement {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.popupBody {
|
||||
font-size: 14px;
|
||||
background-color: #ffd9d9;
|
||||
padding: 5px;
|
||||
padding: 0px 5px;
|
||||
}
|
||||
|
||||
.discreteLink.popupElement {
|
||||
214
public/popup.html
Normal file
@@ -0,0 +1,214 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>__MSG_openPopup__</title>
|
||||
<link id="sponsorBlockPopupFont" rel="stylesheet" type="text/css" href="/libs/Source+Sans+Pro.css"/>
|
||||
<link id="sponsorBlockStyleSheet" rel="stylesheet" type="text/css" href="popup.css"/>
|
||||
</head>
|
||||
|
||||
<body class="popupBody">
|
||||
<center>
|
||||
<div id="app" class="popupBody sponsorBlockPageBody">
|
||||
<h1 class="popupElement">
|
||||
<img src="icons/IconSponsorBlocker256px.png" height="32px" id="sponsorBlockPopupLogo"/>
|
||||
__MSG_Name__
|
||||
</h1>
|
||||
|
||||
<!-- Loading text -->
|
||||
<p id="loadingIndicator" class="popupElement">__MSG_noVideoID__</p>
|
||||
|
||||
<!-- Hidden until loading complete -->
|
||||
<div id="mainControls" class="main popupElement" style="display: none">
|
||||
<!-- If the video was found in the database -->
|
||||
<div id="videoFound">
|
||||
|
||||
</div>
|
||||
|
||||
<div id="downloadedSponsorMessageTimes" class="popupElement">
|
||||
|
||||
</div>
|
||||
|
||||
<p class="popupElement">
|
||||
__MSG_recordTimesDescription__
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<button id="sponsorStart" class="greenButton popupElement">__MSG_sponsorStart__</button>
|
||||
</div>
|
||||
|
||||
<sub class="popupElement">__MSG_popupHint__</sub>
|
||||
|
||||
<div id="submissionSection" class="popupElement" style="display: none">
|
||||
<h3 class="popupElement">__MSG_lastTimes__</h3>
|
||||
<b>
|
||||
<div id="sponsorMessageTimes" class="popupElement">
|
||||
|
||||
</div>
|
||||
</b>
|
||||
|
||||
<br/>
|
||||
|
||||
<button id="clearTimes" class="smallButton popupElement">__MSG_clearTimesButton__</button>
|
||||
|
||||
<div id="submitTimesContainer" class="popupElement" style="display: none">
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="submitTimes" class="smallButton popupElement">__MSG_submitTimesButton__</button>
|
||||
|
||||
<div id="submitTimesInfoMessageContainer" class="popupElement" style="display: none">
|
||||
<h3 id="submitTimesInfoMessage" class="popupElement">
|
||||
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="discordButtonContainer" class="popupElement" style="display: none">
|
||||
<br/>
|
||||
|
||||
<a href="https://discord.gg/QnmVMpU" class="popupElement" target="_blank"><img src="https://www.logolynx.com/images/logolynx/1b/1bcc0f0aefe71b2c8ce66ffe8645d365.png" height="32px"/></a>
|
||||
|
||||
<br/>
|
||||
|
||||
__MSG_discordAdvert__
|
||||
|
||||
<br/>
|
||||
|
||||
<span id="hideDiscordButton" class="smallLink popupElement">__MSG_hideThis__</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<br/>
|
||||
|
||||
<button id="whitelistChannel" class="whitelistButton popupElement">__MSG_whitelistChannel__</button>
|
||||
<button id="unwhitelistChannel" class="whitelistButton popupElement" style="display: none">__MSG_removeFromWhitelist__</button>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<button id="reportAnIssue" class="dangerButton popupElement">__MSG_voteOnTime__</button>
|
||||
|
||||
<div id="issueReporterContainer" class="popupElement" style="display: none">
|
||||
|
||||
<h3 style="margin-top: 0px" class="popupElement">__MSG_voteOnTime__</h3>
|
||||
|
||||
<div id="issueReporterTimeButtons" class="popupElement">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button id="disableSkipping" class="greenButton popupElement">__MSG_disableSkipping__</button>
|
||||
<button id="enableSkipping" class="whitelistButton popupElement" style="display: none">__MSG_enableSkipping__</button>
|
||||
</div>
|
||||
|
||||
<h2 class="recordingSubtitle popupElement">__MSG_yourWork__</h2>
|
||||
|
||||
<p class="popupElement">
|
||||
<span id="sponsorTimesContributionsContainer" class="popupElement" style="display: none">
|
||||
__MSG_soFarUHSubmited__
|
||||
<span id="sponsorTimesContributionsDisplay" class="popupElement">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimesContributionsDisplayEndWord" class="popupElement">__MSG_Sponsors__</span>.
|
||||
</span>
|
||||
|
||||
<span id="sponsorTimesViewsContainer" class="popupElement" style="display: none">
|
||||
__MSG_savedPeopleFrom__
|
||||
<span id="sponsorTimesViewsDisplay" class="popupElement">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimesViewsDisplayEndWord" class="popupElement">__MSG_Segments__</span>.
|
||||
</span>
|
||||
|
||||
<span id="sponsorTimesOthersTimeSavedContainer" class="popupElement" style="display: none">
|
||||
__MSG_youHaveSavedTime__
|
||||
<span id="sponsorTimesOthersTimeSavedDisplay" class="popupElement">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimesOthersTimeSavedEndWord" class="popupElement">__MSG_minsLower__</span>
|
||||
|
||||
<span class="popupElement">__MSG_youHaveSavedTimeEnd__</span>
|
||||
</span>
|
||||
|
||||
<div id="sponsorTimesSkipsDoneContainer" class="popupElement" style="display: none">
|
||||
__MSG_youHaveSkipped__
|
||||
<span id="sponsorTimesSkipsDoneDisplay" class="popupElement">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimesSkipsDoneEndWord" class="popupElement">__MSG_Segments__</span> (since February).
|
||||
</div>
|
||||
|
||||
<div id="sponsorTimeSavedContainer" class="popupElement" style="display: none">
|
||||
__MSG_youHaveSaved__
|
||||
<span id="sponsorTimeSavedDisplay" class="popupElement">
|
||||
0
|
||||
</span>
|
||||
<span id="sponsorTimeSavedEndWord" class="popupElement">__MSG_minsLower__</span>.
|
||||
|
||||
</br/>
|
||||
</br/>
|
||||
</div>
|
||||
|
||||
<div class="popupElement">
|
||||
__MSG_viewLeaderboard__ <a class="popupElement discreteLink" href="https://sponsor.ajay.app/stats" target="_blank">__MSG_here__</a>.
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<div id="setUsernameContainer" class="popupElement">
|
||||
|
||||
<button id="setUsernameButton" class="warningButton popupElement">__MSG_setUsername__</button>
|
||||
<br/>
|
||||
<sub class="popupElement">
|
||||
__MSG_publicStats__ <a class="popupElement discreteLink" href="https://sponsor.ajay.app/stats" target="_blank">__MSG_here__</a>.
|
||||
</sub>
|
||||
</div>
|
||||
|
||||
<div id="setUsername" class="popupElement" style="display: none">
|
||||
<h3>__MSG_setUsername__</h3>
|
||||
|
||||
<div id="setUsernameStatusContainer" style="display: none">
|
||||
<h2 id="setUsernameStatus"></h2>
|
||||
</div>
|
||||
|
||||
<input id="usernameInput" hint="Username"></input>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="submitUsername" class="warningButton popupElement">__MSG_setUsername__</button>
|
||||
</div>
|
||||
|
||||
<div id="optionsButtonContainer" class="popupElement">
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="optionsButton" class="dangerButton popupElement">__MSG_Options__</button>
|
||||
|
||||
<br/>
|
||||
|
||||
<sub class="popupElement">
|
||||
__MSG_optionsInfo__
|
||||
</sub>
|
||||
|
||||
<br/>
|
||||
</div>
|
||||
|
||||
<button id="showNoticeAgain" style="display: none" class="dangerButton popupElement">__MSG_showNotice__</button>
|
||||
</div>
|
||||
</center>
|
||||
</body>
|
||||
|
||||
<!-- Scripts that need to load after the html -->
|
||||
<script src="./js/vendor.js"></script>
|
||||
<script src="./js/popup.js"></script>
|
||||
</html>
|
||||
243
src/background.ts
Normal file
@@ -0,0 +1,243 @@
|
||||
import * as Types from "./types";
|
||||
|
||||
import Config from "./config";
|
||||
// Make the config public for debugging purposes
|
||||
(<any> window).SB = Config;
|
||||
|
||||
import Utils from "./utils";
|
||||
var utils = new Utils({
|
||||
registerFirefoxContentScript,
|
||||
unregisterFirefoxContentScript
|
||||
});
|
||||
|
||||
// Used only on Firefox, which does not support non persistent background pages.
|
||||
var contentScriptRegistrations = {};
|
||||
|
||||
// Register content script if needed
|
||||
if (utils.isFirefox()) {
|
||||
utils.wait(() => Config.config !== null).then(function() {
|
||||
if (Config.config.supportInvidious) utils.setupExtraSiteContentScripts();
|
||||
});
|
||||
}
|
||||
|
||||
chrome.tabs.onUpdated.addListener(function(tabId) {
|
||||
chrome.tabs.sendMessage(tabId, {
|
||||
message: 'update',
|
||||
}, () => void chrome.runtime.lastError ); // Suppress error on Firefox
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||
switch(request.message) {
|
||||
case "openConfig":
|
||||
chrome.runtime.openOptionsPage();
|
||||
return
|
||||
case "submitTimes":
|
||||
submitTimes(request.videoID, callback);
|
||||
|
||||
//this allows the callback to be called later by the submitTimes function
|
||||
return true;
|
||||
case "addSponsorTime":
|
||||
addSponsorTime(request.time, request.videoID, callback);
|
||||
|
||||
//this allows the callback to be called later
|
||||
return true;
|
||||
|
||||
case "getSponsorTimes":
|
||||
getSponsorTimes(request.videoID, function(sponsorTimes) {
|
||||
callback({
|
||||
sponsorTimes
|
||||
});
|
||||
});
|
||||
|
||||
//this allows the callback to be called later
|
||||
return true;
|
||||
case "submitVote":
|
||||
submitVote(request.type, request.UUID, callback);
|
||||
|
||||
//this allows the callback to be called later
|
||||
return true;
|
||||
case "alertPrevious":
|
||||
chrome.notifications.create("stillThere" + Math.random(), {
|
||||
type: "basic",
|
||||
title: chrome.i18n.getMessage("wantToSubmit") + " " + request.previousVideoID + "?",
|
||||
message: chrome.i18n.getMessage("leftTimes"),
|
||||
iconUrl: "./icons/LogoSponsorBlocker256px.png"
|
||||
});
|
||||
case "registerContentScript":
|
||||
registerFirefoxContentScript(request);
|
||||
return false;
|
||||
case "unregisterContentScript":
|
||||
unregisterFirefoxContentScript(request.id)
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
//add help page on install
|
||||
chrome.runtime.onInstalled.addListener(function (object) {
|
||||
// This let's the config sync to run fully before checking.
|
||||
// This is required on Firefox
|
||||
setTimeout(function() {
|
||||
const userID = Config.config.userID;
|
||||
|
||||
// If there is no userID, then it is the first install.
|
||||
if (!userID){
|
||||
//open up the install page
|
||||
chrome.tabs.create({url: chrome.extension.getURL("/help/index_en.html")});
|
||||
|
||||
//generate a userID
|
||||
const newUserID = utils.generateUserID();
|
||||
//save this UUID
|
||||
Config.config.userID = newUserID;
|
||||
|
||||
//TODO: Remove when mobile support is old
|
||||
// Don't show this to new users
|
||||
// Config.config.mobileUpdateShowCount = 1;
|
||||
}
|
||||
}, 1500);
|
||||
});
|
||||
|
||||
/**
|
||||
* Only works on Firefox.
|
||||
* Firefox requires that it be applied after every extension restart.
|
||||
*
|
||||
* @param {JSON} options
|
||||
*/
|
||||
function registerFirefoxContentScript(options) {
|
||||
let oldRegistration = contentScriptRegistrations[options.id];
|
||||
if (oldRegistration) oldRegistration.unregister();
|
||||
|
||||
browser.contentScripts.register({
|
||||
allFrames: options.allFrames,
|
||||
js: options.js,
|
||||
css: options.css,
|
||||
matches: options.matches
|
||||
}).then((registration) => void (contentScriptRegistrations[options.id] = registration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Only works on Firefox.
|
||||
* Firefox requires that this is handled by the background script
|
||||
*
|
||||
*/
|
||||
function unregisterFirefoxContentScript(id: string) {
|
||||
contentScriptRegistrations[id].unregister();
|
||||
delete contentScriptRegistrations[id];
|
||||
}
|
||||
|
||||
//gets the sponsor times from memory
|
||||
function getSponsorTimes(videoID, callback) {
|
||||
let sponsorTimes = [];
|
||||
let sponsorTimesStorage = Config.config.sponsorTimes.get(videoID);
|
||||
|
||||
if (sponsorTimesStorage != undefined && sponsorTimesStorage.length > 0) {
|
||||
sponsorTimes = sponsorTimesStorage;
|
||||
}
|
||||
|
||||
callback(sponsorTimes);
|
||||
}
|
||||
|
||||
function addSponsorTime(time, videoID, callback) {
|
||||
getSponsorTimes(videoID, function(sponsorTimes) {
|
||||
//add to sponsorTimes
|
||||
if (sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length < 2) {
|
||||
//it is an end time
|
||||
sponsorTimes[sponsorTimes.length - 1][1] = time;
|
||||
} else {
|
||||
//it is a start time
|
||||
let sponsorTimesIndex = sponsorTimes.length;
|
||||
sponsorTimes[sponsorTimesIndex] = [];
|
||||
|
||||
sponsorTimes[sponsorTimesIndex][0] = time;
|
||||
}
|
||||
|
||||
//save this info
|
||||
Config.config.sponsorTimes.set(videoID, sponsorTimes);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function submitVote(type, UUID, callback) {
|
||||
let userID = Config.config.userID;
|
||||
|
||||
if (userID == undefined || userID === "undefined") {
|
||||
//generate one
|
||||
userID = utils.generateUserID();
|
||||
Config.config.userID = userID;
|
||||
}
|
||||
|
||||
//publish this vote
|
||||
utils.sendRequestToServer("POST", "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp, error) {
|
||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||
callback({
|
||||
successType: 1
|
||||
});
|
||||
} else if (xmlhttp.readyState == 4 && xmlhttp.status == 405) {
|
||||
//duplicate vote
|
||||
callback({
|
||||
successType: 0,
|
||||
statusCode: xmlhttp.status
|
||||
});
|
||||
} else if (error) {
|
||||
//error while connect
|
||||
callback({
|
||||
successType: -1,
|
||||
statusCode: xmlhttp.status
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
async function submitTimes(videoID, callback) {
|
||||
//get the video times from storage
|
||||
let sponsorTimes = Config.config.sponsorTimes.get(videoID);
|
||||
let userID = Config.config.userID;
|
||||
|
||||
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
|
||||
let durationResult = <Types.videoDurationResponse> await new Promise((resolve, reject) => {
|
||||
chrome.tabs.query({
|
||||
active: true,
|
||||
currentWindow: true
|
||||
}, function(tabs) {
|
||||
chrome.tabs.sendMessage(tabs[0].id, {
|
||||
message: "getVideoDuration"
|
||||
}, (response) => resolve(response));
|
||||
});
|
||||
});
|
||||
|
||||
//check if a sponsor exceeds the duration of the video
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
if (sponsorTimes[i][1] > durationResult.duration) {
|
||||
sponsorTimes[i][1] = durationResult.duration;
|
||||
}
|
||||
}
|
||||
|
||||
//submit these times
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
//to prevent it from happeneing twice
|
||||
let increasedContributionAmount = false;
|
||||
|
||||
//submit the sponsorTime
|
||||
utils.sendRequestToServer("GET", "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1]
|
||||
+ "&userID=" + userID, function(xmlhttp, error) {
|
||||
if (xmlhttp.readyState == 4 && !error) {
|
||||
callback({
|
||||
statusCode: xmlhttp.status
|
||||
});
|
||||
|
||||
if (xmlhttp.status == 200) {
|
||||
//save the amount contributed
|
||||
if (!increasedContributionAmount) {
|
||||
increasedContributionAmount = true;
|
||||
Config.config.sponsorTimesContributed = Config.config.sponsorTimesContributed + sponsorTimes.length;
|
||||
}
|
||||
} else if (error) {
|
||||
callback({
|
||||
statusCode: -1
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
260
src/config.ts
Normal file
@@ -0,0 +1,260 @@
|
||||
import * as CompileConfig from "../config.json";
|
||||
|
||||
interface SBConfig {
|
||||
userID: string,
|
||||
sponsorTimes: SBMap<string, any>,
|
||||
whitelistedChannels: Array<any>,
|
||||
startSponsorKeybind: string,
|
||||
submitKeybind: string,
|
||||
minutesSaved: number,
|
||||
skipCount: number,
|
||||
sponsorTimesContributed: number,
|
||||
disableSkipping: boolean,
|
||||
disableAutoSkip: boolean,
|
||||
trackViewCount: boolean,
|
||||
dontShowNotice: boolean,
|
||||
hideVideoPlayerControls: boolean,
|
||||
hideInfoButtonPlayerControls: boolean,
|
||||
hideDeleteButtonPlayerControls: boolean,
|
||||
hideUploadButtonPlayerControls: boolean,
|
||||
hideDiscordLaunches: number,
|
||||
hideDiscordLink: boolean,
|
||||
invidiousInstances: string[],
|
||||
autoUpvote: boolean,
|
||||
supportInvidious: boolean,
|
||||
serverAddress: string,
|
||||
minDuration: number,
|
||||
checkForUnlistedVideos: boolean,
|
||||
mobileUpdateShowCount: number
|
||||
}
|
||||
|
||||
interface SBObject {
|
||||
configListeners: Array<Function>;
|
||||
defaults: SBConfig;
|
||||
localConfig: SBConfig;
|
||||
config: SBConfig;
|
||||
}
|
||||
|
||||
// Allows a SBMap to be conveted into json form
|
||||
// Currently used for local storage
|
||||
class SBMap<T, U> extends Map {
|
||||
id: string;
|
||||
|
||||
constructor(id: string, entries?: [T, U][]) {
|
||||
super();
|
||||
|
||||
this.id = id;
|
||||
|
||||
// Import all entries if they were given
|
||||
if (entries !== undefined) {
|
||||
for (const item of entries) {
|
||||
super.set(item[0], item[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set(key, value) {
|
||||
const result = super.set(key, value);
|
||||
|
||||
// Store updated SBMap locally
|
||||
chrome.storage.sync.set({
|
||||
[this.id]: encodeStoredItem(this)
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
const result = super.delete(key);
|
||||
|
||||
// Store updated SBMap locally
|
||||
chrome.storage.sync.set({
|
||||
[this.id]: encodeStoredItem(this)
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
clear() {
|
||||
const result = super.clear();
|
||||
|
||||
chrome.storage.sync.set({
|
||||
[this.id]: encodeStoredItem(this)
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
var Config: SBObject = {
|
||||
/**
|
||||
* Callback function when an option is updated
|
||||
*/
|
||||
configListeners: [],
|
||||
defaults: {
|
||||
userID: null,
|
||||
sponsorTimes: new SBMap("sponsorTimes"),
|
||||
whitelistedChannels: [],
|
||||
startSponsorKeybind: ";",
|
||||
submitKeybind: "'",
|
||||
minutesSaved: 0,
|
||||
skipCount: 0,
|
||||
sponsorTimesContributed: 0,
|
||||
disableSkipping: false,
|
||||
disableAutoSkip: false,
|
||||
trackViewCount: true,
|
||||
dontShowNotice: false,
|
||||
hideVideoPlayerControls: false,
|
||||
hideInfoButtonPlayerControls: false,
|
||||
hideDeleteButtonPlayerControls: false,
|
||||
hideUploadButtonPlayerControls: false,
|
||||
hideDiscordLaunches: 0,
|
||||
hideDiscordLink: false,
|
||||
invidiousInstances: ["invidio.us", "invidiou.sh", "invidious.snopyta.org"],
|
||||
autoUpvote: true,
|
||||
supportInvidious: false,
|
||||
serverAddress: CompileConfig.serverAddress,
|
||||
minDuration: 0,
|
||||
checkForUnlistedVideos: false,
|
||||
mobileUpdateShowCount: 0
|
||||
},
|
||||
localConfig: null,
|
||||
config: null
|
||||
};
|
||||
|
||||
// Function setup
|
||||
|
||||
/**
|
||||
* A SBMap cannot be stored in the chrome storage.
|
||||
* This data will be encoded into an array instead
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
function encodeStoredItem(data) {
|
||||
// if data is SBMap convert to json for storing
|
||||
if(!(data instanceof SBMap)) return data;
|
||||
return Array.from(data.entries());
|
||||
}
|
||||
|
||||
/**
|
||||
* An SBMap cannot be stored in the chrome storage.
|
||||
* This data will be decoded from the array it is stored in
|
||||
*
|
||||
* @param {*} data
|
||||
*/
|
||||
function decodeStoredItem(id: string, data) {
|
||||
if (!Config.defaults[id]) return data;
|
||||
|
||||
if (Config.defaults[id] instanceof SBMap) {
|
||||
try {
|
||||
let jsonData: any = data;
|
||||
|
||||
// Check if data is stored in the old format for SBMap (a JSON string)
|
||||
if (typeof data === "string") {
|
||||
try {
|
||||
jsonData = JSON.parse(data);
|
||||
} catch(e) {
|
||||
// Continue normally (out of this if statement)
|
||||
}
|
||||
}
|
||||
|
||||
if (!Array.isArray(jsonData)) return data;
|
||||
return new SBMap(id, jsonData);
|
||||
} catch(e) {
|
||||
console.error("Failed to parse SBMap: " + id);
|
||||
}
|
||||
}
|
||||
|
||||
// If all else fails, return the data
|
||||
return data;
|
||||
}
|
||||
|
||||
function configProxy(): any {
|
||||
chrome.storage.onChanged.addListener((changes, namespace) => {
|
||||
for (const key in changes) {
|
||||
Config.localConfig[key] = decodeStoredItem(key, changes[key].newValue);
|
||||
}
|
||||
|
||||
for (const callback of Config.configListeners) {
|
||||
callback(changes);
|
||||
}
|
||||
});
|
||||
|
||||
var handler: ProxyHandler<any> = {
|
||||
set(obj, prop, value) {
|
||||
Config.localConfig[prop] = value;
|
||||
|
||||
chrome.storage.sync.set({
|
||||
[prop]: encodeStoredItem(value)
|
||||
});
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
get(obj, prop): any {
|
||||
let data = Config.localConfig[prop];
|
||||
|
||||
return obj[prop] || data;
|
||||
},
|
||||
|
||||
deleteProperty(obj, prop) {
|
||||
chrome.storage.sync.remove(<string> prop);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return new Proxy({handler}, handler);
|
||||
}
|
||||
|
||||
function fetchConfig() {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.storage.sync.get(null, function(items) {
|
||||
Config.localConfig = <SBConfig> <unknown> items; // Data is ready
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function migrateOldFormats() { // Convert sponsorTimes format
|
||||
for (const key in Config.localConfig) {
|
||||
if (key.startsWith("sponsorTimes") && key !== "sponsorTimes" && key !== "sponsorTimesContributed") {
|
||||
Config.config.sponsorTimes.set(key.substr(12), Config.config[key]);
|
||||
delete Config.config[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function setupConfig() {
|
||||
await fetchConfig();
|
||||
addDefaults();
|
||||
convertJSON();
|
||||
Config.config = configProxy();
|
||||
migrateOldFormats();
|
||||
}
|
||||
|
||||
// Reset config
|
||||
function resetConfig() {
|
||||
Config.config = Config.defaults;
|
||||
};
|
||||
|
||||
function convertJSON() {
|
||||
Object.keys(Config.localConfig).forEach(key => {
|
||||
Config.localConfig[key] = decodeStoredItem(key, Config.localConfig[key]);
|
||||
});
|
||||
}
|
||||
|
||||
// Add defaults
|
||||
function addDefaults() {
|
||||
for (const key in Config.defaults) {
|
||||
if(!Config.localConfig.hasOwnProperty(key)) {
|
||||
Config.localConfig[key] = Config.defaults[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Sync config
|
||||
setupConfig();
|
||||
|
||||
export default Config;
|
||||
1462
src/content.ts
Normal file
@@ -13,29 +13,47 @@ let barTypes = {
|
||||
"sponsor": {
|
||||
color: "#00d400",
|
||||
opacity: "0.5"
|
||||
},
|
||||
"previewSponsor": {
|
||||
color: "#0000d4",
|
||||
opacity: "0.5"
|
||||
}
|
||||
};
|
||||
|
||||
class PreviewBar {
|
||||
constructor(parent) {
|
||||
container: HTMLUListElement;
|
||||
parent: any;
|
||||
onMobileYouTube: boolean;
|
||||
|
||||
constructor(parent, onMobileYouTube) {
|
||||
this.container = document.createElement('ul');
|
||||
this.container.id = 'previewbar';
|
||||
this.parent = parent;
|
||||
this.bars = []
|
||||
|
||||
this.updatePosition();
|
||||
this.onMobileYouTube = onMobileYouTube;
|
||||
|
||||
this.updatePosition(parent);
|
||||
}
|
||||
|
||||
updatePosition() {
|
||||
updatePosition(parent) {
|
||||
//below the seek bar
|
||||
// this.parent.insertAdjacentElement("afterEnd", this.container);
|
||||
|
||||
this.parent = parent;
|
||||
|
||||
if (this.onMobileYouTube) {
|
||||
parent.style.backgroundColor = "rgba(255, 255, 255, 0.3)";
|
||||
parent.style.opacity = "1";
|
||||
|
||||
this.container.style.transform = "none";
|
||||
}
|
||||
|
||||
//on the seek bar
|
||||
this.parent.insertAdjacentElement("afterBegin", this.container);
|
||||
}
|
||||
|
||||
updateColor(segment, color, opacity) {
|
||||
let bars = document.querySelectorAll('[data-vs-segment-type=' + segment + ']');
|
||||
let bars = <NodeListOf<HTMLElement>> document.querySelectorAll('[data-vs-segment-type=' + segment + ']');
|
||||
for (let bar of bars) {
|
||||
bar.style.backgroundColor = color;
|
||||
bar.style.opacity = opacity;
|
||||
@@ -55,6 +73,8 @@ class PreviewBar {
|
||||
duration = Math.floor(duration * 100) / 100;
|
||||
let width;
|
||||
for (let i = 0; i < timestamps.length; i++) {
|
||||
if (types[i] == null) continue;
|
||||
|
||||
width = (timestamps[i][1] - timestamps[i][0]) / duration * 100;
|
||||
width = Math.floor(width * 100) / 100;
|
||||
|
||||
@@ -62,13 +82,12 @@ class PreviewBar {
|
||||
bar.setAttribute('data-vs-segment-type', types[i]);
|
||||
|
||||
bar.style.backgroundColor = barTypes[types[i]].color;
|
||||
bar.style.opacity = barTypes[types[i]].opacity;
|
||||
if (!this.onMobileYouTube) bar.style.opacity = barTypes[types[i]].opacity;
|
||||
bar.style.width = width + '%';
|
||||
bar.style.left = (timestamps[i][0] / duration * 100) + "%";
|
||||
bar.style.position = "absolute"
|
||||
|
||||
this.container.insertAdjacentElement('beforeEnd', bar);
|
||||
this.bars[i] = bar;
|
||||
this.container.insertAdjacentElement("beforeend", bar);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,4 +102,6 @@ class PreviewBar {
|
||||
this.container.remove();
|
||||
this.container = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default PreviewBar;
|
||||
@@ -1,16 +1,40 @@
|
||||
'use strict';
|
||||
|
||||
//The notice that tells the user that a sponsor was just skipped
|
||||
import Config from "../config";
|
||||
|
||||
/**
|
||||
* The notice that tells the user that a sponsor was just skipped
|
||||
*/
|
||||
class SkipNotice {
|
||||
constructor(parent, UUID) {
|
||||
parent: HTMLElement;
|
||||
UUID: string;
|
||||
manualSkip: boolean;
|
||||
// Contains functions and variables from the content script needed by the skip notice
|
||||
contentContainer: () => any;
|
||||
|
||||
maxCountdownTime: () => number;
|
||||
countdownTime: any;
|
||||
countdownInterval: NodeJS.Timeout;
|
||||
unskipCallback: any;
|
||||
idSuffix: any;
|
||||
|
||||
constructor(parent: HTMLElement, UUID: string, manualSkip: boolean = false, contentContainer) {
|
||||
this.parent = parent;
|
||||
this.UUID = UUID;
|
||||
this.manualSkip = manualSkip;
|
||||
this.contentContainer = contentContainer;
|
||||
|
||||
let noticeTitle = chrome.i18n.getMessage("noticeTitle");
|
||||
|
||||
if (manualSkip) {
|
||||
noticeTitle = chrome.i18n.getMessage("noticeTitleNotSkipped");
|
||||
}
|
||||
|
||||
this.maxCountdownTime = () => 4;
|
||||
//the countdown until this notice closes
|
||||
this.countdownTime = this.maxCountdownTime();
|
||||
//the id for the setInterval running the countdown
|
||||
this.countdownInterval = -1;
|
||||
this.countdownInterval = null;
|
||||
|
||||
//the unskip button's callback
|
||||
this.unskipCallback = this.unskip.bind(this);
|
||||
@@ -33,7 +57,11 @@ class SkipNotice {
|
||||
noticeElement.id = "sponsorSkipNotice" + this.idSuffix;
|
||||
noticeElement.classList.add("sponsorSkipObject");
|
||||
noticeElement.classList.add("sponsorSkipNotice");
|
||||
noticeElement.style.zIndex = 50 + amountOfPreviousNotices;
|
||||
noticeElement.style.zIndex = String(50 + amountOfPreviousNotices);
|
||||
if (contentContainer().onMobileYouTube) {
|
||||
noticeElement.style.bottom = "4em";
|
||||
noticeElement.style.transform = "scale(0.8) translate(10%, 10%)";
|
||||
}
|
||||
|
||||
//add mouse enter and leave listeners
|
||||
noticeElement.addEventListener("mouseenter", this.pauseCountdown.bind(this));
|
||||
@@ -54,7 +82,7 @@ class SkipNotice {
|
||||
noticeMessage.id = "sponsorSkipMessage" + this.idSuffix;
|
||||
noticeMessage.classList.add("sponsorSkipMessage");
|
||||
noticeMessage.classList.add("sponsorSkipObject");
|
||||
noticeMessage.innerText = chrome.i18n.getMessage("noticeTitle");
|
||||
noticeMessage.innerText = noticeTitle;
|
||||
|
||||
//create the first column
|
||||
logoColumn.appendChild(logoElement);
|
||||
@@ -106,7 +134,7 @@ class SkipNotice {
|
||||
downvoteButton.id = "sponsorTimesDownvoteButtonsContainer" + this.idSuffix;
|
||||
downvoteButton.className = "sponsorSkipObject voteButton";
|
||||
downvoteButton.src = chrome.extension.getURL("icons/report.png");
|
||||
downvoteButton.addEventListener("click", () => vote(0, this.UUID, this));
|
||||
downvoteButton.addEventListener("click", () => this.contentContainer().vote(0, this.UUID, this));
|
||||
downvoteButton.setAttribute("title", chrome.i18n.getMessage("reportButtonInfo"));
|
||||
|
||||
//add downvote and report text to container
|
||||
@@ -134,9 +162,12 @@ class SkipNotice {
|
||||
let dontShowAgainButton = document.createElement("button");
|
||||
dontShowAgainButton.innerText = chrome.i18n.getMessage("Hide");
|
||||
dontShowAgainButton.className = "sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeRightButton";
|
||||
dontShowAgainButton.addEventListener("click", dontShowNoticeAgain);
|
||||
dontShowAgainButton.addEventListener("click", this.contentContainer().dontShowNoticeAgain);
|
||||
|
||||
dontshowContainer.appendChild(dontShowAgainButton);
|
||||
// Don't let them hide it if manually skipping
|
||||
if (!this.manualSkip) {
|
||||
dontshowContainer.appendChild(dontShowAgainButton);
|
||||
}
|
||||
|
||||
//add to row
|
||||
secondRow.appendChild(voteButtonsContainer);
|
||||
@@ -148,16 +179,17 @@ class SkipNotice {
|
||||
noticeElement.appendChild(secondRow);
|
||||
|
||||
//get reference node
|
||||
let referenceNode = document.getElementById("movie_player");
|
||||
let referenceNode = document.getElementById("player-container-id")
|
||||
|| document.getElementById("movie_player") || document.querySelector("#player-container .video-js");
|
||||
if (referenceNode == null) {
|
||||
//for embeds
|
||||
let player = document.getElementById("player");
|
||||
referenceNode = player.firstChild;
|
||||
referenceNode = <HTMLElement> player.firstChild;
|
||||
let index = 1;
|
||||
|
||||
//find the child that is the video player (sometimes it is not the first)
|
||||
while (!referenceNode.classList.contains("html5-video-player") || !referenceNode.classList.contains("ytp-embed")) {
|
||||
referenceNode = player.children[index];
|
||||
referenceNode = <HTMLElement> player.children[index];
|
||||
|
||||
index++;
|
||||
}
|
||||
@@ -165,6 +197,10 @@ class SkipNotice {
|
||||
|
||||
referenceNode.prepend(noticeElement);
|
||||
|
||||
if (manualSkip) {
|
||||
this.unskippedMode(chrome.i18n.getMessage("skip"));
|
||||
}
|
||||
|
||||
this.startCountdown();
|
||||
}
|
||||
|
||||
@@ -195,7 +231,7 @@ class SkipNotice {
|
||||
pauseCountdown() {
|
||||
//remove setInterval
|
||||
clearInterval(this.countdownInterval);
|
||||
this.countdownInterval = -1;
|
||||
this.countdownInterval = null;
|
||||
|
||||
//reset countdown
|
||||
this.countdownTime = this.maxCountdownTime();
|
||||
@@ -212,7 +248,7 @@ class SkipNotice {
|
||||
|
||||
startCountdown() {
|
||||
//if it has already started, don't start it again
|
||||
if (this.countdownInterval != -1) return;
|
||||
if (this.countdownInterval !== null) return;
|
||||
|
||||
this.countdownInterval = setInterval(this.countdown.bind(this), 1000);
|
||||
|
||||
@@ -226,12 +262,15 @@ class SkipNotice {
|
||||
}
|
||||
|
||||
unskip() {
|
||||
unskipSponsorTime(this.UUID);
|
||||
this.contentContainer().unskipSponsorTime(this.UUID);
|
||||
|
||||
this.unskippedMode(chrome.i18n.getMessage("reskip"));
|
||||
}
|
||||
|
||||
/** Sets up notice to be not skipped yet */
|
||||
unskippedMode(buttonText) {
|
||||
//change unskip button to a reskip button
|
||||
let unskipButton = document.getElementById("sponsorSkipUnskipButton" + this.idSuffix);
|
||||
unskipButton.innerText = chrome.i18n.getMessage("reskip");
|
||||
unskipButton.removeEventListener("click", this.unskipCallback);
|
||||
let unskipButton = this.changeUnskipButton(buttonText);
|
||||
|
||||
//setup new callback
|
||||
this.unskipCallback = this.reskip.bind(this);
|
||||
@@ -239,8 +278,8 @@ class SkipNotice {
|
||||
|
||||
//change max duration to however much of the sponsor is left
|
||||
this.maxCountdownTime = function() {
|
||||
let sponsorTime = sponsorTimes[UUIDs.indexOf(this.UUID)];
|
||||
let duration = Math.round(sponsorTime[1] - v.currentTime);
|
||||
let sponsorTime = this.contentContainer().sponsorTimes[this.contentContainer().UUIDs.indexOf(this.UUID)];
|
||||
let duration = Math.round(sponsorTime[1] - this.contentContainer().v.currentTime);
|
||||
|
||||
return Math.max(duration, 4);
|
||||
};
|
||||
@@ -250,12 +289,10 @@ class SkipNotice {
|
||||
}
|
||||
|
||||
reskip() {
|
||||
reskipSponsorTime(this.UUID);
|
||||
this.contentContainer().reskipSponsorTime(this.UUID);
|
||||
|
||||
//change unskip button to a reskip button
|
||||
let unskipButton = document.getElementById("sponsorSkipUnskipButton" + this.idSuffix);
|
||||
unskipButton.innerText = chrome.i18n.getMessage("unskip");
|
||||
unskipButton.removeEventListener("click", this.unskipCallback);
|
||||
//change reskip button to a unskip button
|
||||
let unskipButton = this.changeUnskipButton(chrome.i18n.getMessage("unskip"));
|
||||
|
||||
//setup new callback
|
||||
this.unskipCallback = this.unskip.bind(this);
|
||||
@@ -265,6 +302,27 @@ class SkipNotice {
|
||||
this.maxCountdownTime = () => 4;
|
||||
this.countdownTime = this.maxCountdownTime();
|
||||
this.updateTimerDisplay();
|
||||
|
||||
// See if the title should be changed
|
||||
if (this.manualSkip) {
|
||||
this.changeNoticeTitle(chrome.i18n.getMessage("noticeTitle"));
|
||||
|
||||
if (Config.config.autoUpvote) this.contentContainer().vote(1, this.UUID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the text on the reskip button
|
||||
*
|
||||
* @param {string} text
|
||||
* @returns {HTMLElement} unskipButton
|
||||
*/
|
||||
changeUnskipButton(text) {
|
||||
let unskipButton = document.getElementById("sponsorSkipUnskipButton" + this.idSuffix);
|
||||
unskipButton.innerText = text;
|
||||
unskipButton.removeEventListener("click", this.unskipCallback);
|
||||
|
||||
return unskipButton;
|
||||
}
|
||||
|
||||
afterDownvote() {
|
||||
@@ -273,42 +331,56 @@ class SkipNotice {
|
||||
|
||||
//remove this sponsor from the sponsors looked up
|
||||
//find which one it is
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
if (UUIDs[i] == this.UUID) {
|
||||
for (let i = 0; i < this.contentContainer().sponsorTimes.length; i++) {
|
||||
if (this.contentContainer().UUIDs[i] == this.UUID) {
|
||||
//this one is the one to hide
|
||||
|
||||
//add this as a hidden sponsorTime
|
||||
hiddenSponsorTimes.push(i);
|
||||
|
||||
let sponsorTimesLeft = sponsorTimes.slice();
|
||||
for (let j = 0; j < hiddenSponsorTimes.length; j++) {
|
||||
//remove this sponsor time
|
||||
sponsorTimesLeft.splice(hiddenSponsorTimes[j], 1);
|
||||
}
|
||||
|
||||
//update the preview
|
||||
previewBar.set(sponsorTimesLeft, [], v.duration);
|
||||
this.contentContainer().hiddenSponsorTimes.push(i);
|
||||
|
||||
this.contentContainer().updatePreviewBar();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changeNoticeTitle(title) {
|
||||
let noticeElement = document.getElementById("sponsorSkipMessage" + this.idSuffix);
|
||||
|
||||
noticeElement.innerText = title;
|
||||
}
|
||||
|
||||
addNoticeInfoMessage(message) {
|
||||
addNoticeInfoMessage(message: string, message2: string = "") {
|
||||
let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix);
|
||||
if (previousInfoMessage != null) {
|
||||
//remove it
|
||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage);
|
||||
}
|
||||
|
||||
let previousInfoMessage2 = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix + "2");
|
||||
if (previousInfoMessage2 != null) {
|
||||
//remove it
|
||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage2);
|
||||
}
|
||||
|
||||
//add info
|
||||
let thanksForVotingText = document.createElement("p");
|
||||
thanksForVotingText.id = "sponsorTimesInfoMessage" + this.idSuffix;
|
||||
thanksForVotingText.className = "sponsorTimesInfoMessage";
|
||||
thanksForVotingText.innerText = message;
|
||||
|
||||
|
||||
//add element to div
|
||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).insertBefore(thanksForVotingText, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix));
|
||||
|
||||
if (message2 !== undefined) {
|
||||
let thanksForVotingText2 = document.createElement("p");
|
||||
thanksForVotingText2.id = "sponsorTimesInfoMessage" + this.idSuffix + "2";
|
||||
thanksForVotingText2.className = "sponsorTimesInfoMessage";
|
||||
thanksForVotingText2.innerText = message2;
|
||||
|
||||
//add element to div
|
||||
document.getElementById("sponsorSkipNotice" + this.idSuffix).insertBefore(thanksForVotingText2, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix));
|
||||
}
|
||||
}
|
||||
|
||||
resetNoticeInfoMessage() {
|
||||
@@ -337,7 +409,7 @@ class SkipNotice {
|
||||
thanksForVotingText.id = "sponsorTimesVoteButtonInfoMessage" + this.idSuffix;
|
||||
thanksForVotingText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage";
|
||||
thanksForVotingText.innerText = message;
|
||||
|
||||
|
||||
//add element to div
|
||||
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).prepend(thanksForVotingText);
|
||||
}
|
||||
@@ -348,17 +420,25 @@ class SkipNotice {
|
||||
//remove it
|
||||
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).removeChild(previousInfoMessage);
|
||||
}
|
||||
|
||||
|
||||
//show button again
|
||||
document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix).style.removeProperty("display");
|
||||
}
|
||||
|
||||
//close this notice
|
||||
close() {
|
||||
//reset message
|
||||
this.resetNoticeInfoMessage();
|
||||
|
||||
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||
if (notice != null) {
|
||||
notice.remove();
|
||||
}
|
||||
|
||||
//remove setInterval
|
||||
if (this.countdownInterval !== null) clearInterval(this.countdownInterval);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default SkipNotice;
|
||||
435
src/options.ts
Normal file
@@ -0,0 +1,435 @@
|
||||
import Config from "./config";
|
||||
// Make the config public for debugging purposes
|
||||
(<any> window).SB = Config;
|
||||
|
||||
import Utils from "./utils";
|
||||
var utils = new Utils();
|
||||
|
||||
window.addEventListener('DOMContentLoaded', init);
|
||||
|
||||
async function init() {
|
||||
utils.localizeHtmlPage();
|
||||
|
||||
if (!Config.configListeners.includes(optionsConfigUpdateListener)) {
|
||||
Config.configListeners.push(optionsConfigUpdateListener);
|
||||
}
|
||||
|
||||
await utils.wait(() => Config.config !== null);
|
||||
|
||||
// Set all of the toggle options to the correct option
|
||||
let optionsContainer = document.getElementById("options");
|
||||
let optionsElements = optionsContainer.querySelectorAll("*");
|
||||
|
||||
for (let i = 0; i < optionsElements.length; i++) {
|
||||
switch (optionsElements[i].getAttribute("option-type")) {
|
||||
case "toggle":
|
||||
let option = optionsElements[i].getAttribute("sync-option");
|
||||
let optionResult = Config.config[option];
|
||||
|
||||
let checkbox = optionsElements[i].querySelector("input");
|
||||
let reverse = optionsElements[i].getAttribute("toggle-type") === "reverse";
|
||||
|
||||
if (optionResult != undefined) {
|
||||
checkbox.checked = optionResult;
|
||||
|
||||
if (reverse) {
|
||||
optionsElements[i].querySelector("input").checked = !optionResult;
|
||||
}
|
||||
}
|
||||
|
||||
// See if anything extra should be run first time
|
||||
switch (option) {
|
||||
case "supportInvidious":
|
||||
invidiousInit(checkbox, option);
|
||||
break;
|
||||
}
|
||||
|
||||
// Add click listener
|
||||
checkbox.addEventListener("click", () => {
|
||||
Config.config[option] = reverse ? !checkbox.checked : checkbox.checked;
|
||||
|
||||
// See if anything extra must be run
|
||||
switch (option) {
|
||||
case "supportInvidious":
|
||||
invidiousOnClick(checkbox, option);
|
||||
break;
|
||||
case "disableAutoSkip":
|
||||
if (!checkbox.checked) {
|
||||
// Enable the notice
|
||||
Config.config["dontShowNotice"] = false;
|
||||
|
||||
let showNoticeSwitch = <HTMLInputElement> document.querySelector("[sync-option='dontShowNotice'] > label > label > input");
|
||||
showNoticeSwitch.checked = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "text-change":
|
||||
let textChangeOption = optionsElements[i].getAttribute("sync-option");
|
||||
let textChangeInput = <HTMLInputElement> optionsElements[i].querySelector(".option-text-box");
|
||||
|
||||
let textChangeSetButton = <HTMLElement> optionsElements[i].querySelector(".text-change-set");
|
||||
|
||||
textChangeInput.value = Config.config[textChangeOption];
|
||||
|
||||
textChangeSetButton.addEventListener("click", async () => {
|
||||
// See if anything extra must be done
|
||||
switch (textChangeOption) {
|
||||
case "serverAddress":
|
||||
let result = validateServerAddress(textChangeInput.value);
|
||||
|
||||
if (result !== null) {
|
||||
textChangeInput.value = result;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Permission needed on Firefox
|
||||
if (utils.isFirefox()) {
|
||||
let permissionSuccess = await new Promise((resolve, reject) => {
|
||||
chrome.permissions.request({
|
||||
origins: [textChangeInput.value + "/"],
|
||||
permissions: []
|
||||
}, resolve);
|
||||
});
|
||||
|
||||
if (!permissionSuccess) return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Config.config[textChangeOption] = textChangeInput.value;
|
||||
});
|
||||
|
||||
// Reset to the default if needed
|
||||
let textChangeResetButton = <HTMLElement> optionsElements[i].querySelector(".text-change-reset");
|
||||
textChangeResetButton.addEventListener("click", () => {
|
||||
if (!confirm(chrome.i18n.getMessage("areYouSureReset"))) return;
|
||||
|
||||
Config.config[textChangeOption] = Config.defaults[textChangeOption];
|
||||
|
||||
textChangeInput.value = Config.config[textChangeOption];
|
||||
});
|
||||
|
||||
break;
|
||||
case "private-text-change":
|
||||
let button = optionsElements[i].querySelector(".trigger-button");
|
||||
button.addEventListener("click", () => activatePrivateTextChange(<HTMLElement> optionsElements[i]));
|
||||
|
||||
let privateTextChangeOption = optionsElements[i].getAttribute("sync-option");
|
||||
// See if anything extra must be done
|
||||
switch (privateTextChangeOption) {
|
||||
case "invidiousInstances":
|
||||
invidiousInstanceAddInit(<HTMLElement> optionsElements[i], privateTextChangeOption);
|
||||
}
|
||||
|
||||
break;
|
||||
case "keybind-change":
|
||||
let keybindButton = optionsElements[i].querySelector(".trigger-button");
|
||||
keybindButton.addEventListener("click", () => activateKeybindChange(<HTMLElement> optionsElements[i]));
|
||||
|
||||
break;
|
||||
case "display":
|
||||
updateDisplayElement(<HTMLElement> optionsElements[i])
|
||||
|
||||
break;
|
||||
case "number-change":
|
||||
let numberChangeOption = optionsElements[i].getAttribute("sync-option");
|
||||
let configValue = Config.config[numberChangeOption];
|
||||
let numberInput = optionsElements[i].querySelector("input");
|
||||
|
||||
if (isNaN(configValue) || configValue < 0) {
|
||||
numberInput.value = Config.defaults[numberChangeOption];
|
||||
} else {
|
||||
numberInput.value = configValue;
|
||||
}
|
||||
|
||||
numberInput.addEventListener("input", () => {
|
||||
Config.config[numberChangeOption] = numberInput.value;
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
optionsContainer.classList.remove("hidden");
|
||||
optionsContainer.classList.add("animated");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the config is updated
|
||||
*
|
||||
* @param {String} element
|
||||
*/
|
||||
function optionsConfigUpdateListener(changes) {
|
||||
let optionsContainer = document.getElementById("options");
|
||||
let optionsElements = optionsContainer.querySelectorAll("*");
|
||||
|
||||
for (let i = 0; i < optionsElements.length; i++) {
|
||||
switch (optionsElements[i].getAttribute("option-type")) {
|
||||
case "display":
|
||||
updateDisplayElement(<HTMLElement> optionsElements[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will set display elements to the proper text
|
||||
*
|
||||
* @param element
|
||||
*/
|
||||
function updateDisplayElement(element: HTMLElement) {
|
||||
let displayOption = element.getAttribute("sync-option")
|
||||
let displayText = Config.config[displayOption];
|
||||
element.innerText = displayText;
|
||||
|
||||
// See if anything extra must be run
|
||||
switch (displayOption) {
|
||||
case "invidiousInstances":
|
||||
element.innerText = displayText.join(', ');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the option to add Invidious instances
|
||||
*
|
||||
* @param element
|
||||
* @param option
|
||||
*/
|
||||
function invidiousInstanceAddInit(element: HTMLElement, option: string) {
|
||||
let textBox = <HTMLInputElement> element.querySelector(".option-text-box");
|
||||
let button = element.querySelector(".trigger-button");
|
||||
|
||||
let setButton = element.querySelector(".text-change-set");
|
||||
setButton.addEventListener("click", async function(e) {
|
||||
if (textBox.value == "" || textBox.value.includes("/") || textBox.value.includes("http") || textBox.value.includes(":")) {
|
||||
alert(chrome.i18n.getMessage("addInvidiousInstanceError"));
|
||||
} else {
|
||||
// Add this
|
||||
let instanceList = Config.config[option];
|
||||
if (!instanceList) instanceList = [];
|
||||
|
||||
instanceList.push(textBox.value);
|
||||
|
||||
Config.config[option] = instanceList;
|
||||
|
||||
let checkbox = <HTMLInputElement> document.querySelector("#support-invidious input");
|
||||
checkbox.checked = true;
|
||||
|
||||
invidiousOnClick(checkbox, "supportInvidious");
|
||||
|
||||
textBox.value = "";
|
||||
|
||||
// Hide this section again
|
||||
element.querySelector(".option-hidden-section").classList.add("hidden");
|
||||
button.classList.remove("disabled");
|
||||
}
|
||||
});
|
||||
|
||||
let resetButton = element.querySelector(".invidious-instance-reset");
|
||||
resetButton.addEventListener("click", function(e) {
|
||||
if (confirm(chrome.i18n.getMessage("resetInvidiousInstanceAlert"))) {
|
||||
// Set to a clone of the default
|
||||
Config.config[option] = Config.defaults[option].slice(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Run when the invidious button is being initialized
|
||||
*
|
||||
* @param checkbox
|
||||
* @param option
|
||||
*/
|
||||
function invidiousInit(checkbox: HTMLInputElement, option: string) {
|
||||
let permissions = ["declarativeContent"];
|
||||
if (utils.isFirefox()) permissions = [];
|
||||
|
||||
chrome.permissions.contains({
|
||||
origins: utils.getInvidiousInstancesRegex(),
|
||||
permissions: permissions
|
||||
}, function (result) {
|
||||
if (result != checkbox.checked) {
|
||||
Config.config[option] = result;
|
||||
|
||||
checkbox.checked = result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Run whenever the invidious checkbox is clicked
|
||||
*
|
||||
* @param checkbox
|
||||
* @param option
|
||||
*/
|
||||
function invidiousOnClick(checkbox: HTMLInputElement, option: string) {
|
||||
if (checkbox.checked) {
|
||||
utils.setupExtraSitePermissions(function (granted) {
|
||||
if (!granted) {
|
||||
Config.config[option] = false;
|
||||
checkbox.checked = false;
|
||||
} else {
|
||||
checkbox.checked = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
utils.removeExtraSiteRegistration();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will trigger the container to ask the user for a keybind.
|
||||
*
|
||||
* @param element
|
||||
*/
|
||||
function activateKeybindChange(element: HTMLElement) {
|
||||
let button = element.querySelector(".trigger-button");
|
||||
if (button.classList.contains("disabled")) return;
|
||||
|
||||
button.classList.add("disabled");
|
||||
|
||||
let option = element.getAttribute("sync-option");
|
||||
|
||||
let currentlySet = Config.config[option] !== null ? chrome.i18n.getMessage("keybindCurrentlySet") : "";
|
||||
|
||||
let status = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status");
|
||||
status.innerText = chrome.i18n.getMessage("keybindDescription") + currentlySet;
|
||||
|
||||
if (Config.config[option] !== null) {
|
||||
let statusKey = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status-key");
|
||||
statusKey.innerText = Config.config[option];
|
||||
}
|
||||
|
||||
element.querySelector(".option-hidden-section").classList.remove("hidden");
|
||||
|
||||
document.addEventListener("keydown", (e) => keybindKeyPressed(element, e), {once: true});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a key is pressed in an activiated keybind change option.
|
||||
*
|
||||
* @param element
|
||||
* @param e
|
||||
*/
|
||||
function keybindKeyPressed(element: HTMLElement, e: KeyboardEvent) {
|
||||
var key = e.key;
|
||||
|
||||
let button = element.querySelector(".trigger-button");
|
||||
|
||||
// cancel setting a keybind
|
||||
if (key === "Escape") {
|
||||
element.querySelector(".option-hidden-section").classList.add("hidden");
|
||||
button.classList.remove("disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
let option = element.getAttribute("sync-option");
|
||||
|
||||
Config.config[option] = key;
|
||||
|
||||
let status = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status");
|
||||
status.innerText = chrome.i18n.getMessage("keybindDescriptionComplete");
|
||||
|
||||
let statusKey = <HTMLElement> element.querySelector(".option-hidden-section > .keybind-status-key");
|
||||
statusKey.innerText = key;
|
||||
|
||||
button.classList.remove("disabled");
|
||||
}
|
||||
|
||||
/**
|
||||
* Will trigger the textbox to appear to be able to change an option's text.
|
||||
*
|
||||
* @param element
|
||||
*/
|
||||
function activatePrivateTextChange(element: HTMLElement) {
|
||||
let button = element.querySelector(".trigger-button");
|
||||
if (button.classList.contains("disabled")) return;
|
||||
|
||||
button.classList.add("disabled");
|
||||
|
||||
let textBox = <HTMLInputElement> element.querySelector(".option-text-box");
|
||||
let option = element.getAttribute("sync-option");
|
||||
|
||||
// See if anything extra must be done
|
||||
switch (option) {
|
||||
case "invidiousInstances":
|
||||
element.querySelector(".option-hidden-section").classList.remove("hidden");
|
||||
return;
|
||||
}
|
||||
|
||||
let result = Config.config[option];
|
||||
|
||||
// See if anything extra must be done
|
||||
switch (option) {
|
||||
case "*":
|
||||
result = JSON.stringify(Config.localConfig);
|
||||
break;
|
||||
}
|
||||
|
||||
textBox.value = result;
|
||||
|
||||
let setButton = element.querySelector(".text-change-set");
|
||||
setButton.addEventListener("click", () => {
|
||||
let confirmMessage = element.getAttribute("confirm-message");
|
||||
|
||||
if (confirmMessage === null || confirm(chrome.i18n.getMessage(confirmMessage))) {
|
||||
|
||||
// See if anything extra must be done
|
||||
switch (option) {
|
||||
case "*":
|
||||
try {
|
||||
let newConfig = JSON.parse(textBox.value);
|
||||
for (const key in newConfig) {
|
||||
Config.config[key] = newConfig[key];
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
if (newConfig.supportInvidious) {
|
||||
let checkbox = <HTMLInputElement> document.querySelector("#support-invidious > label > label > input");
|
||||
|
||||
checkbox.checked = true;
|
||||
invidiousOnClick(checkbox, "supportInvidious");
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
alert(chrome.i18n.getMessage("incorrectlyFormattedOptions"));
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
Config.config[option] = textBox.value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
element.querySelector(".option-hidden-section").classList.remove("hidden");
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the value used for the database server address.
|
||||
* Returns null and alerts the user if there is an issue.
|
||||
*
|
||||
* @param input Input server address
|
||||
*/
|
||||
function validateServerAddress(input: string): string {
|
||||
input = input.trim();
|
||||
|
||||
// Trim the trailing slashes
|
||||
input = input.replace(/\/+$/, "");
|
||||
|
||||
// If it isn't HTTP protocol
|
||||
if ((!input.startsWith("https://") && !input.startsWith("http://"))) {
|
||||
|
||||
alert(chrome.i18n.getMessage("customAddressError"));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
7
src/types.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
interface videoDurationResponse {
|
||||
duration: number;
|
||||
}
|
||||
|
||||
export {
|
||||
videoDurationResponse
|
||||
};
|
||||
267
src/utils.ts
Normal file
@@ -0,0 +1,267 @@
|
||||
import Config from "./config";
|
||||
|
||||
class Utils {
|
||||
|
||||
// Contains functions needed from the background script
|
||||
backgroundScriptContainer: any = null;
|
||||
|
||||
// Used to add content scripts and CSS required
|
||||
js = [
|
||||
"./js/vendor.js",
|
||||
"./js/content.js"
|
||||
];
|
||||
css = [
|
||||
"content.css",
|
||||
"./libs/Source+Sans+Pro.css",
|
||||
"popup.css"
|
||||
];
|
||||
|
||||
constructor(backgroundScriptContainer?: any) {
|
||||
this.backgroundScriptContainer = backgroundScriptContainer;
|
||||
}
|
||||
|
||||
// Function that can be used to wait for a condition before returning
|
||||
async wait(condition, timeout = 5000, check = 100) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
setTimeout(() => reject("TIMEOUT"), timeout);
|
||||
|
||||
let intervalCheck = () => {
|
||||
let result = condition();
|
||||
if (result !== false) {
|
||||
resolve(result);
|
||||
clearInterval(interval);
|
||||
};
|
||||
};
|
||||
|
||||
let interval = setInterval(intervalCheck, check);
|
||||
|
||||
//run the check once first, this speeds it up a lot
|
||||
intervalCheck();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks for the optional permissions required for all extra sites.
|
||||
* It also starts the content script registrations.
|
||||
*
|
||||
* For now, it is just SB.config.invidiousInstances.
|
||||
*
|
||||
* @param {CallableFunction} callback
|
||||
*/
|
||||
setupExtraSitePermissions(callback) {
|
||||
// Request permission
|
||||
let permissions = ["declarativeContent"];
|
||||
if (this.isFirefox()) permissions = [];
|
||||
|
||||
let self = this;
|
||||
|
||||
chrome.permissions.request({
|
||||
origins: this.getInvidiousInstancesRegex(),
|
||||
permissions: permissions
|
||||
}, async function (granted) {
|
||||
if (granted) {
|
||||
self.setupExtraSiteContentScripts();
|
||||
} else {
|
||||
self.removeExtraSiteRegistration();
|
||||
}
|
||||
|
||||
callback(granted);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the content scripts for the extra sites.
|
||||
* Will use a different method depending on the browser.
|
||||
* This is called by setupExtraSitePermissions().
|
||||
*
|
||||
* For now, it is just SB.config.invidiousInstances.
|
||||
*/
|
||||
setupExtraSiteContentScripts() {
|
||||
let self = this;
|
||||
|
||||
if (this.isFirefox()) {
|
||||
let firefoxJS = [];
|
||||
for (const file of this.js) {
|
||||
firefoxJS.push({file});
|
||||
}
|
||||
let firefoxCSS = [];
|
||||
for (const file of this.css) {
|
||||
firefoxCSS.push({file});
|
||||
}
|
||||
|
||||
let registration = {
|
||||
message: "registerContentScript",
|
||||
id: "invidious",
|
||||
allFrames: true,
|
||||
js: firefoxJS,
|
||||
css: firefoxCSS,
|
||||
matches: this.getInvidiousInstancesRegex()
|
||||
};
|
||||
|
||||
if (this.backgroundScriptContainer) {
|
||||
this.backgroundScriptContainer.registerFirefoxContentScript(registration);
|
||||
} else {
|
||||
chrome.runtime.sendMessage(registration);
|
||||
}
|
||||
} else {
|
||||
chrome.declarativeContent.onPageChanged.removeRules(["invidious"], function() {
|
||||
let conditions = [];
|
||||
for (const regex of self.getInvidiousInstancesRegex()) {
|
||||
conditions.push(new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { urlMatches: regex }
|
||||
}));
|
||||
}
|
||||
|
||||
// Add page rule
|
||||
let rule = {
|
||||
id: "invidious",
|
||||
conditions,
|
||||
// This API is experimental and not visible by the TypeScript compiler
|
||||
actions: [new (<any> chrome.declarativeContent).RequestContentScript({
|
||||
allFrames: true,
|
||||
js: self.js,
|
||||
css: self.css
|
||||
})]
|
||||
};
|
||||
|
||||
chrome.declarativeContent.onPageChanged.addRules([rule]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the permission and content script registration.
|
||||
*/
|
||||
removeExtraSiteRegistration() {
|
||||
if (this.isFirefox()) {
|
||||
let id = "invidious";
|
||||
|
||||
if (this.backgroundScriptContainer) {
|
||||
this.backgroundScriptContainer.unregisterFirefoxContentScript(id);
|
||||
} else {
|
||||
chrome.runtime.sendMessage({
|
||||
message: "unregisterContentScript",
|
||||
id: id
|
||||
});
|
||||
}
|
||||
} else if (chrome.declarativeContent) {
|
||||
// Only if we have permission
|
||||
chrome.declarativeContent.onPageChanged.removeRules(["invidious"]);
|
||||
}
|
||||
|
||||
chrome.permissions.remove({
|
||||
origins: this.getInvidiousInstancesRegex()
|
||||
});
|
||||
}
|
||||
|
||||
localizeHtmlPage() {
|
||||
//Localize by replacing __MSG_***__ meta tags
|
||||
var objects = document.getElementsByClassName("sponsorBlockPageBody")[0].children;
|
||||
for (var j = 0; j < objects.length; j++) {
|
||||
var obj = objects[j];
|
||||
|
||||
let localizedMessage = this.getLocalizedMessage(obj.innerHTML.toString());
|
||||
if (localizedMessage) obj.innerHTML = localizedMessage;
|
||||
}
|
||||
}
|
||||
|
||||
getLocalizedMessage(text) {
|
||||
var valNewH = text.replace(/__MSG_(\w+)__/g, function(match, v1) {
|
||||
return v1 ? chrome.i18n.getMessage(v1) : "";
|
||||
});
|
||||
|
||||
if(valNewH != text) {
|
||||
return valNewH;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {String[]} Invidious Instances in regex form
|
||||
*/
|
||||
getInvidiousInstancesRegex() {
|
||||
var invidiousInstancesRegex = [];
|
||||
for (const url of Config.config.invidiousInstances) {
|
||||
invidiousInstancesRegex.push("https://*." + url + "/*");
|
||||
invidiousInstancesRegex.push("http://*." + url + "/*");
|
||||
}
|
||||
|
||||
return invidiousInstancesRegex;
|
||||
}
|
||||
|
||||
generateUserID(length = 36) {
|
||||
let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let result = "";
|
||||
if (window.crypto && window.crypto.getRandomValues) {
|
||||
let values = new Uint32Array(length);
|
||||
window.crypto.getRandomValues(values);
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += charset[values[i] % charset.length];
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += charset[Math.floor(Math.random() * charset.length)];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error message in a nice string
|
||||
*
|
||||
* @param {int} statusCode
|
||||
* @returns {string} errorMessage
|
||||
*/
|
||||
getErrorMessage(statusCode) {
|
||||
let errorMessage = "";
|
||||
|
||||
if([400, 429, 409, 502, 0].includes(statusCode)) {
|
||||
//treat them the same
|
||||
if (statusCode == 503) statusCode = 502;
|
||||
|
||||
errorMessage = chrome.i18n.getMessage(statusCode + "") + " " + chrome.i18n.getMessage("errorCode") + statusCode
|
||||
+ "\n\n" + chrome.i18n.getMessage("statusReminder");
|
||||
} else {
|
||||
errorMessage = chrome.i18n.getMessage("connectionError") + statusCode;
|
||||
}
|
||||
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to the SponsorBlock server with address added as a query
|
||||
*
|
||||
* @param type The request type. "GET", "POST", etc.
|
||||
* @param address The address to add to the SponsorBlock server address
|
||||
* @param callback
|
||||
*/
|
||||
sendRequestToServer(type: string, address: string, callback?: (xmlhttp: XMLHttpRequest, err: boolean) => any) {
|
||||
let xmlhttp = new XMLHttpRequest();
|
||||
|
||||
xmlhttp.open(type, Config.config.serverAddress + address, true);
|
||||
|
||||
if (callback != undefined) {
|
||||
xmlhttp.onreadystatechange = function () {
|
||||
callback(xmlhttp, false);
|
||||
};
|
||||
|
||||
xmlhttp.onerror = function(ev) {
|
||||
callback(xmlhttp, true);
|
||||
};
|
||||
}
|
||||
|
||||
//submit this request
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this Firefox (web-extensions)
|
||||
*/
|
||||
isFirefox() {
|
||||
return typeof(browser) !== "undefined";
|
||||
}
|
||||
}
|
||||
|
||||
export default Utils;
|
||||
12
tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"noImplicitAny": false,
|
||||
"sourceMap": false,
|
||||
"outDir": "dist/js",
|
||||
"noEmitOnError": true,
|
||||
"typeRoots": [ "node_modules/@types" ],
|
||||
"resolveJsonModule": true
|
||||
}
|
||||
}
|
||||
37
utils.js
@@ -1,37 +0,0 @@
|
||||
function getYouTubeVideoID(url) {
|
||||
//Attempt to parse url
|
||||
let urlObject = null;
|
||||
try {
|
||||
urlObject = new URL(url);
|
||||
} catch (e) {
|
||||
console.error("[SB] Unable to parse URL: " + url);
|
||||
return false
|
||||
}
|
||||
|
||||
//Check if valid hostname
|
||||
if(!["www.youtube.com","www.youtube-nocookie.com"].includes(urlObject.host)) return false;
|
||||
|
||||
//Get ID from searchParam
|
||||
if ((urlObject.pathname == "/watch" || urlObject.pathname == "/watch/") && urlObject.searchParams.has("v")) {
|
||||
id = urlObject.searchParams.get("v");
|
||||
return id.length == 11 ? id : false;
|
||||
} else if (urlObject.pathname.startsWith("/embed/")) {
|
||||
try {
|
||||
return urlObject.pathname.substr(7, 11);
|
||||
} catch (e) {
|
||||
console.error("[SB] Video ID not valid for " + url);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//returns the start time of the video if there was one specified (ex. ?t=5s)
|
||||
function getYouTubeVideoStartTime(url) {
|
||||
let searchParams = new URL(url).searchParams;
|
||||
let startTime = searchParams.get("t");
|
||||
if (startTime == null) {
|
||||
startTime = searchParams.get("time_continue");
|
||||
}
|
||||
|
||||
return startTime;
|
||||
}
|
||||
49
webpack/webpack.common.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const webpack = require("webpack");
|
||||
const path = require('path');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const BuildManifest = require('./webpack.manifest');
|
||||
const srcDir = '../src/';
|
||||
|
||||
module.exports = env => ({
|
||||
entry: {
|
||||
popup: path.join(__dirname, srcDir + 'popup.ts'),
|
||||
background: path.join(__dirname, srcDir + 'background.ts'),
|
||||
content: path.join(__dirname, srcDir + 'content.ts'),
|
||||
options: path.join(__dirname, srcDir + 'options.ts')
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, '../dist/js'),
|
||||
filename: '[name].js'
|
||||
},
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
name: 'vendor',
|
||||
chunks: "initial"
|
||||
}
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js']
|
||||
},
|
||||
plugins: [
|
||||
// exclude locale files in moment
|
||||
new CopyPlugin([
|
||||
{ from: '.', to: '../', ignore: ['manifest.json'] }
|
||||
],
|
||||
{context: 'public' }
|
||||
),
|
||||
new BuildManifest({
|
||||
browser: env.browser,
|
||||
pretty: env.mode === "production",
|
||||
stream: env.stream
|
||||
})
|
||||
]
|
||||
});
|
||||
7
webpack/webpack.dev.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const merge = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
|
||||
module.exports = env => merge(common(env), {
|
||||
devtool: 'inline-source-map',
|
||||
mode: 'development'
|
||||
});
|
||||
80
webpack/webpack.manifest.js
Normal file
@@ -0,0 +1,80 @@
|
||||
const webpack = require("webpack");
|
||||
const path = require('path');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const validateOptions = require('schema-utils');
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const manifest = require("../manifest/manifest.json");
|
||||
const firefoxManifestExtra = require("../manifest/firefox-manifest-extra.json");
|
||||
const chromeManifestExtra = require("../manifest/chrome-manifest-extra.json");
|
||||
const betaManifestExtra = require("../manifest/beta-manifest-extra.json");
|
||||
const firefoxBetaManifestExtra = require("../manifest/firefox-beta-manifest-extra.json");
|
||||
|
||||
// schema for options object
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
browser: {
|
||||
type: 'string'
|
||||
},
|
||||
pretty: {
|
||||
type: 'boolean'
|
||||
},
|
||||
steam: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class BuildManifest {
|
||||
constructor (options = {}) {
|
||||
validateOptions(schema, options, "Build Manifest Plugin");
|
||||
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
const distFolder = path.resolve(__dirname, "../dist/");
|
||||
const distManifestFile = path.resolve(distFolder, "manifest.json");
|
||||
|
||||
// Add missing manifest elements
|
||||
if (this.options.browser.toLowerCase() === "firefox") {
|
||||
mergeObjects(manifest, firefoxManifestExtra);
|
||||
} else if (this.options.browser.toLowerCase() === "chrome" || this.options.browser.toLowerCase() === "chromium") {
|
||||
mergeObjects(manifest, chromeManifestExtra);
|
||||
}
|
||||
|
||||
if (this.options.stream === "beta") {
|
||||
mergeObjects(manifest, betaManifestExtra);
|
||||
|
||||
if (this.options.browser.toLowerCase() === "firefox") {
|
||||
mergeObjects(manifest, firefoxBetaManifestExtra);
|
||||
}
|
||||
}
|
||||
|
||||
let result = JSON.stringify(manifest);
|
||||
if (this.options.pretty) result = JSON.stringify(manifest, null, 2);
|
||||
|
||||
fs.mkdirSync(distFolder, {recursive: true});
|
||||
fs.writeFileSync(distManifestFile, result);
|
||||
}
|
||||
}
|
||||
|
||||
function mergeObjects(object1, object2) {
|
||||
for (const key in object2) {
|
||||
if (key in object1) {
|
||||
if (Array.isArray(object1[key])) {
|
||||
object1[key] = object1[key].concat(object2[key]);
|
||||
} else if (typeof object1[key] == 'object') {
|
||||
mergeObjects(object1[key], object2[key]);
|
||||
} else {
|
||||
object1[key] = object2[key];
|
||||
}
|
||||
} else {
|
||||
object1[key] = object2[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BuildManifest;
|
||||
11
webpack/webpack.prod.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const merge = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
|
||||
module.exports = env => {
|
||||
let mode = "production";
|
||||
env.mode = mode;
|
||||
|
||||
return merge(common(env), {
|
||||
mode
|
||||
});
|
||||
};
|
||||