mirror of
https://github.com/sabnzbd/sabnzbd.git
synced 2025-12-24 08:08:37 -05:00
Compare commits
2508 Commits
3.0.0Beta2
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63c03b42a9 | ||
|
|
4539837fad | ||
|
|
a0cd48e3f5 | ||
|
|
ceeb7cb162 | ||
|
|
f9f4e1b028 | ||
|
|
6487944c6c | ||
|
|
239fddf39c | ||
|
|
8ada8b2fd9 | ||
|
|
b19bd65495 | ||
|
|
e3ea5fdd64 | ||
|
|
4fdb89701a | ||
|
|
9165c4f304 | ||
|
|
4152f0ba6a | ||
|
|
3eaab17739 | ||
|
|
578bfd083d | ||
|
|
dd464456e4 | ||
|
|
e7a0255359 | ||
|
|
2e1281d9e8 | ||
|
|
efecefdd3b | ||
|
|
a91e718ef5 | ||
|
|
b420975267 | ||
|
|
c4211df8dc | ||
|
|
e182707d3a | ||
|
|
05cbd9d7c4 | ||
|
|
6e8683349f | ||
|
|
adb4816552 | ||
|
|
3914290c11 | ||
|
|
f76bf55b4a | ||
|
|
1cde764336 | ||
|
|
44d94226ec | ||
|
|
e8e8fff5bf | ||
|
|
1b04e07d40 | ||
|
|
54db889f05 | ||
|
|
777d279267 | ||
|
|
75be6b5850 | ||
|
|
a4657e2bd3 | ||
|
|
095b48ca47 | ||
|
|
d459f69113 | ||
|
|
2ecdd0b940 | ||
|
|
73a4ad50e5 | ||
|
|
9b59e24961 | ||
|
|
27e164763e | ||
|
|
eb544d85c7 | ||
|
|
ad85a241df | ||
|
|
e4d8642b4f | ||
|
|
77b35e7904 | ||
|
|
f8a0b3db52 | ||
|
|
9c8b26ab4e | ||
|
|
67a5a552fd | ||
|
|
80f57a2b9a | ||
|
|
baaf7edc89 | ||
|
|
2d9f480af1 | ||
|
|
2266ac33aa | ||
|
|
1ba479398c | ||
|
|
f71a81f7a8 | ||
|
|
1916c01bd9 | ||
|
|
699d97965c | ||
|
|
399935ad21 | ||
|
|
0824fdc7c7 | ||
|
|
a3f8e89af8 | ||
|
|
f9f17731c8 | ||
|
|
b052325ea7 | ||
|
|
daca14f97e | ||
|
|
daa26bc1a6 | ||
|
|
70d5134d28 | ||
|
|
a32458d9a9 | ||
|
|
4c77954526 | ||
|
|
a229a2a5ea | ||
|
|
0a2f3865ee | ||
|
|
900e68bb9a | ||
|
|
1de674a532 | ||
|
|
e1dad3e4c4 | ||
|
|
44f2eb8620 | ||
|
|
70945a9c5b | ||
|
|
fdfca97dfa | ||
|
|
b84900dcb5 | ||
|
|
d989ec928a | ||
|
|
d7fa3e1f7b | ||
|
|
c1417c319d | ||
|
|
6689939cc9 | ||
|
|
09347d0766 | ||
|
|
41db09057c | ||
|
|
6983058f49 | ||
|
|
fb2d412c97 | ||
|
|
1c0b1205b2 | ||
|
|
f556cea488 | ||
|
|
a2447253a0 | ||
|
|
3393d7c976 | ||
|
|
06572bdf7d | ||
|
|
d4411f1b8f | ||
|
|
1bfd1b8f41 | ||
|
|
c47dbfdc26 | ||
|
|
b5e55cd9b2 | ||
|
|
85c98d7203 | ||
|
|
9e95717619 | ||
|
|
90b4ff2720 | ||
|
|
0f97a9fdfc | ||
|
|
90caf0c164 | ||
|
|
9b3fe470a0 | ||
|
|
ab318729ab | ||
|
|
9576554426 | ||
|
|
3cd819b78d | ||
|
|
bb24f3f04e | ||
|
|
6f4416236d | ||
|
|
47dcccd17f | ||
|
|
6b026d8274 | ||
|
|
ec18606557 | ||
|
|
895c8549ba | ||
|
|
0d80efb898 | ||
|
|
deace9f8ae | ||
|
|
1c96dff133 | ||
|
|
1734b11338 | ||
|
|
5f3c4d17da | ||
|
|
4ffe0e27fb | ||
|
|
951bc0c957 | ||
|
|
60f985ba00 | ||
|
|
a42a2db196 | ||
|
|
64034c5636 | ||
|
|
e03a031342 | ||
|
|
da3d72b484 | ||
|
|
e3042a6106 | ||
|
|
55f1253a56 | ||
|
|
5e432bea37 | ||
|
|
2d0cc08987 | ||
|
|
627797f8c7 | ||
|
|
e37a777f29 | ||
|
|
13a76e5824 | ||
|
|
e4c64cac12 | ||
|
|
c6694483e4 | ||
|
|
bc793e11c4 | ||
|
|
4980fc70a0 | ||
|
|
8afac4f6fb | ||
|
|
c78b633da8 | ||
|
|
a1ee1677dc | ||
|
|
511bb153d7 | ||
|
|
c1af36f6b0 | ||
|
|
6028824966 | ||
|
|
49a7300ad6 | ||
|
|
8e8e560eac | ||
|
|
e51da569ca | ||
|
|
6ce43eed5f | ||
|
|
73ec6d8323 | ||
|
|
27a7531f79 | ||
|
|
423bdb4f81 | ||
|
|
7f8081e2cc | ||
|
|
50c2d5e2ab | ||
|
|
552bfd4b72 | ||
|
|
3d522c8205 | ||
|
|
b6b0d10367 | ||
|
|
8d4d69d56b | ||
|
|
0e475e593a | ||
|
|
78424318ce | ||
|
|
57c90b2554 | ||
|
|
9b94d22621 | ||
|
|
5c30b0ee29 | ||
|
|
3a1c60a3ed | ||
|
|
bd07a79c97 | ||
|
|
c562c9a468 | ||
|
|
fdd3f590cd | ||
|
|
77e9627e64 | ||
|
|
c40d1274d2 | ||
|
|
d1948071fc | ||
|
|
4f79d924e6 | ||
|
|
872cf835df | ||
|
|
69bb1a87a4 | ||
|
|
e3339a1ab4 | ||
|
|
18d84fa522 | ||
|
|
7a7e7b7b93 | ||
|
|
18ca9d6155 | ||
|
|
f5aa0f52d6 | ||
|
|
5a93074f4b | ||
|
|
3863d6bd2f | ||
|
|
753d1e3bd3 | ||
|
|
5393b6330e | ||
|
|
2d8be8d89b | ||
|
|
08723f0432 | ||
|
|
1e1220c509 | ||
|
|
c6920e09bf | ||
|
|
74d2a9f7c4 | ||
|
|
31c9c64741 | ||
|
|
96e7999b4f | ||
|
|
5303b9d291 | ||
|
|
91af147b8b | ||
|
|
33463a3fd1 | ||
|
|
ac88446757 | ||
|
|
d129eec4a7 | ||
|
|
9b1b908115 | ||
|
|
5866c029c4 | ||
|
|
de6a6a084e | ||
|
|
139489e5b3 | ||
|
|
a91f72a7f4 | ||
|
|
f5fd4c1c18 | ||
|
|
3da67dc4af | ||
|
|
0220d886c5 | ||
|
|
19ea25f072 | ||
|
|
d934c588ad | ||
|
|
ccb036ba37 | ||
|
|
3d1c5c82d1 | ||
|
|
d37532a4eb | ||
|
|
143851d1cb | ||
|
|
235dd32ad0 | ||
|
|
0b295d7b57 | ||
|
|
a4020ed085 | ||
|
|
af1e5e0c1d | ||
|
|
a3fffea9f9 | ||
|
|
180bc30ea5 | ||
|
|
f6b21680f8 | ||
|
|
f6b65a4d1a | ||
|
|
4662bb8129 | ||
|
|
e2f613da6c | ||
|
|
d4874970cd | ||
|
|
80268c4068 | ||
|
|
e2811f93b1 | ||
|
|
f8190e28c9 | ||
|
|
7eb460ba1f | ||
|
|
fe647284e7 | ||
|
|
54fe887636 | ||
|
|
2604775e5c | ||
|
|
a15bad6fb4 | ||
|
|
58c060c39d | ||
|
|
6ecd0a8561 | ||
|
|
4a52289f05 | ||
|
|
104c0b20fe | ||
|
|
b8a3a264e3 | ||
|
|
b0e42940e5 | ||
|
|
4bc6fefa1f | ||
|
|
3ec8227745 | ||
|
|
9f6dc3df01 | ||
|
|
cadeae061f | ||
|
|
80c3226147 | ||
|
|
f2137e2fa3 | ||
|
|
9bf80a3745 | ||
|
|
750ee422a7 | ||
|
|
035559f1c3 | ||
|
|
4751f609bb | ||
|
|
40fde7a411 | ||
|
|
b27a7f6cf4 | ||
|
|
9006875d6c | ||
|
|
dd0122865a | ||
|
|
9a5f39ce99 | ||
|
|
545f75b456 | ||
|
|
e1553e86b6 | ||
|
|
c85ddd0595 | ||
|
|
5d763f52af | ||
|
|
2b842b2bc5 | ||
|
|
2a3e144ed6 | ||
|
|
52f09dbf55 | ||
|
|
6bce289c8f | ||
|
|
20bc8f0d06 | ||
|
|
966fe246f6 | ||
|
|
c4a84b3a31 | ||
|
|
e06f91c243 | ||
|
|
42c00dda84 | ||
|
|
e40d2980e7 | ||
|
|
b6a905be21 | ||
|
|
22800ae411 | ||
|
|
e8a4d95177 | ||
|
|
026a606e7f | ||
|
|
9551f9a3b9 | ||
|
|
f62e7ab560 | ||
|
|
92fbd75cc3 | ||
|
|
7de0869376 | ||
|
|
57606ef1bb | ||
|
|
318d3ff649 | ||
|
|
8953f4df4a | ||
|
|
7c607a6bf6 | ||
|
|
93c6d67ef8 | ||
|
|
a314d6ab71 | ||
|
|
62bb9b3816 | ||
|
|
2ef5cec5c5 | ||
|
|
c8e2329bee | ||
|
|
f0358d9f0a | ||
|
|
3f89114c73 | ||
|
|
721f5dfe86 | ||
|
|
ef38c1d7c8 | ||
|
|
fe88760600 | ||
|
|
e498ef6302 | ||
|
|
b1c486fa2a | ||
|
|
d9aa42dc31 | ||
|
|
3ee0db8cff | ||
|
|
23cae4d073 | ||
|
|
2b45ba044e | ||
|
|
cd831d2775 | ||
|
|
8c761ba67e | ||
|
|
07243290ec | ||
|
|
317a9c00de | ||
|
|
cc40214818 | ||
|
|
3b52379e56 | ||
|
|
8a2f8d969d | ||
|
|
6f9bf68528 | ||
|
|
5a48301d25 | ||
|
|
d1d3e27dea | ||
|
|
2f1805123a | ||
|
|
f05c82b3a7 | ||
|
|
1fe01f2724 | ||
|
|
a5239808eb | ||
|
|
00a7b4fffc | ||
|
|
0c5010f5c1 | ||
|
|
a8b33e7686 | ||
|
|
0294e01fae | ||
|
|
c2621f56eb | ||
|
|
ebac7707ff | ||
|
|
26adade8be | ||
|
|
dd9c7488c6 | ||
|
|
754b862a29 | ||
|
|
0ddf343bb7 | ||
|
|
7a8a45b811 | ||
|
|
66c525ef95 | ||
|
|
7cd3e50ded | ||
|
|
d5094e1aa6 | ||
|
|
bca9559783 | ||
|
|
0cbb8af7a0 | ||
|
|
afab90ca68 | ||
|
|
92ecfc4930 | ||
|
|
b064f112cd | ||
|
|
629da51be7 | ||
|
|
0fa0f7286c | ||
|
|
6cd8f3e333 | ||
|
|
ff18fe03e9 | ||
|
|
a1e30d19e3 | ||
|
|
3d74c19f41 | ||
|
|
33a831e87c | ||
|
|
7b04917f0e | ||
|
|
2f62b76279 | ||
|
|
bd43bca1cf | ||
|
|
d200f0a618 | ||
|
|
c5314569db | ||
|
|
001e215b7d | ||
|
|
3a628a0025 | ||
|
|
7e48207fbc | ||
|
|
48a6d6b289 | ||
|
|
21f05ad3d9 | ||
|
|
d93c861eb3 | ||
|
|
fb0ef21768 | ||
|
|
277679ef53 | ||
|
|
e7e47bbcb0 | ||
|
|
65ffb5ca81 | ||
|
|
6cf308e441 | ||
|
|
870fa40c91 | ||
|
|
39d9eaec2a | ||
|
|
6fd4d0882c | ||
|
|
32591f7c46 | ||
|
|
6b47d1126d | ||
|
|
53df39dd12 | ||
|
|
b5d33fc17c | ||
|
|
8a517b668e | ||
|
|
67135ba4c8 | ||
|
|
c9efda1889 | ||
|
|
250869c242 | ||
|
|
844650e6be | ||
|
|
6685c72894 | ||
|
|
154a5e4989 | ||
|
|
93d302c9d7 | ||
|
|
f664df7f05 | ||
|
|
8fbf50292b | ||
|
|
f3fed43022 | ||
|
|
2d323ba18c | ||
|
|
1ec30a56e1 | ||
|
|
b98f3a07dd | ||
|
|
46170ffb3d | ||
|
|
5e8b41be5a | ||
|
|
47a2d5387d | ||
|
|
1e61239933 | ||
|
|
aedbf35be8 | ||
|
|
cf9540842b | ||
|
|
9205b9161b | ||
|
|
07b64b4abb | ||
|
|
c56145e424 | ||
|
|
ef11aba166 | ||
|
|
fcf03e9a59 | ||
|
|
6662065bb1 | ||
|
|
4973672892 | ||
|
|
efa73a52e1 | ||
|
|
82098a6228 | ||
|
|
07250aa355 | ||
|
|
46caa8b33f | ||
|
|
b0564c1bab | ||
|
|
3c8a85ff35 | ||
|
|
656c329912 | ||
|
|
983253908c | ||
|
|
cef0eeb25b | ||
|
|
a9eace759f | ||
|
|
ad0e7bf5df | ||
|
|
bea348232a | ||
|
|
1519dbc554 | ||
|
|
297455cd35 | ||
|
|
56b68024db | ||
|
|
09aa09a55b | ||
|
|
f1d134fe2e | ||
|
|
621d586c2f | ||
|
|
4966f9c753 | ||
|
|
059d82f6f0 | ||
|
|
bca41db6b7 | ||
|
|
613ba0b05f | ||
|
|
5f3b03ed87 | ||
|
|
f6fe801000 | ||
|
|
8ff34660d8 | ||
|
|
0c1b8dd60a | ||
|
|
8e8ee7a3ab | ||
|
|
9145a90e33 | ||
|
|
02b4a116dd | ||
|
|
e504b288a2 | ||
|
|
5128f788f0 | ||
|
|
044fe7a26a | ||
|
|
4ed2565101 | ||
|
|
abbd77bac4 | ||
|
|
38c9a52e1d | ||
|
|
f89114ca7e | ||
|
|
773d567eed | ||
|
|
ee717b679e | ||
|
|
f50810fb58 | ||
|
|
08b1b20b34 | ||
|
|
edca79af83 | ||
|
|
dd5dcd0ec9 | ||
|
|
820824e443 | ||
|
|
4c2dfdee43 | ||
|
|
ece4437c3a | ||
|
|
74daa15ce4 | ||
|
|
4f81bc8a26 | ||
|
|
e77d15f75e | ||
|
|
8668852574 | ||
|
|
7e944f393e | ||
|
|
1646fbfd17 | ||
|
|
72b0521325 | ||
|
|
8aa53fd43f | ||
|
|
aa67edb2d9 | ||
|
|
0054b17f41 | ||
|
|
2af2cc7370 | ||
|
|
5aa7aafebb | ||
|
|
3bd0f7c1e0 | ||
|
|
9c8d21f6db | ||
|
|
4947effeb7 | ||
|
|
b8fd9e6e31 | ||
|
|
2a02c93e4b | ||
|
|
a0ef520e06 | ||
|
|
a9eb32eba6 | ||
|
|
592ef0e645 | ||
|
|
cce53ee058 | ||
|
|
93755aa6d8 | ||
|
|
b1d42c7c22 | ||
|
|
8286b7b830 | ||
|
|
fbaa3c0420 | ||
|
|
ba6c30cf24 | ||
|
|
3ce5679298 | ||
|
|
47e1d40943 | ||
|
|
1687130107 | ||
|
|
8e59146d60 | ||
|
|
4b37d2772f | ||
|
|
ea9d690a90 | ||
|
|
3a2e967a03 | ||
|
|
a2eb0cc2c3 | ||
|
|
8b9341023a | ||
|
|
54314c0198 | ||
|
|
b0e4c4c5bf | ||
|
|
989e215acc | ||
|
|
ba88bb15a9 | ||
|
|
0cac0d942c | ||
|
|
b24a9ee781 | ||
|
|
25ae29235f | ||
|
|
a8d4de2d3d | ||
|
|
ccb3e0522c | ||
|
|
a9f1838b52 | ||
|
|
d744c293fb | ||
|
|
94848979ad | ||
|
|
2732326b3d | ||
|
|
ea8328c199 | ||
|
|
f1e42707a0 | ||
|
|
c1bdc3abff | ||
|
|
5cbb569b38 | ||
|
|
d4a3f0ea79 | ||
|
|
b31fe2cf49 | ||
|
|
65d748fc9f | ||
|
|
ab2da15bc9 | ||
|
|
bf8bef3cd0 | ||
|
|
adbe2f3c96 | ||
|
|
dadb8ee71b | ||
|
|
7d30f12532 | ||
|
|
9c41cbd2f3 | ||
|
|
5ce9a0c17d | ||
|
|
7b2d2df299 | ||
|
|
285ff00c12 | ||
|
|
04ca95cc83 | ||
|
|
3b25a07522 | ||
|
|
14aa449c35 | ||
|
|
d88c035c23 | ||
|
|
6d2d90b1e5 | ||
|
|
e2ca39fb36 | ||
|
|
6a37780b8e | ||
|
|
146f33f38e | ||
|
|
c6c26c5de4 | ||
|
|
262cc8dbbd | ||
|
|
5bec8e99a5 | ||
|
|
2e0e6749ca | ||
|
|
c0ef18e8b3 | ||
|
|
52173804f1 | ||
|
|
2d8cf69140 | ||
|
|
e2603d74ca | ||
|
|
9df9238d56 | ||
|
|
b697165392 | ||
|
|
16bfcc27d8 | ||
|
|
be3f47539d | ||
|
|
f3fd63cd70 | ||
|
|
aafdf7620e | ||
|
|
4f3b0541eb | ||
|
|
04fb73fd4a | ||
|
|
b1a7924c75 | ||
|
|
4e618206a8 | ||
|
|
8a510331df | ||
|
|
81035964ca | ||
|
|
304cf5eda0 | ||
|
|
b987749291 | ||
|
|
cc3ad230f8 | ||
|
|
e7266db3b3 | ||
|
|
a85f39a6e4 | ||
|
|
14fdb93c07 | ||
|
|
349957b8d4 | ||
|
|
16134c6421 | ||
|
|
608d05fabc | ||
|
|
c410e1209d | ||
|
|
74aefd868a | ||
|
|
55476b6594 | ||
|
|
ad650aa6eb | ||
|
|
154d2d73ef | ||
|
|
b171f7764f | ||
|
|
30a20b549e | ||
|
|
a3cc5e244d | ||
|
|
37441f598f | ||
|
|
8bced7cdc9 | ||
|
|
35d0589f46 | ||
|
|
5c45db3d45 | ||
|
|
700d08c69d | ||
|
|
1b71c60256 | ||
|
|
8cf7d812ab | ||
|
|
627264affd | ||
|
|
674502323b | ||
|
|
34a9d751b8 | ||
|
|
5b252efcf0 | ||
|
|
6756f2ba2e | ||
|
|
3c0e89802e | ||
|
|
e55a95db39 | ||
|
|
80cd64b4ba | ||
|
|
962642b0d0 | ||
|
|
641f353c84 | ||
|
|
d598bc0a79 | ||
|
|
153041c431 | ||
|
|
582a40599a | ||
|
|
6e21f14ae9 | ||
|
|
a4540b8deb | ||
|
|
fe10c7daad | ||
|
|
cd4ee1eee9 | ||
|
|
54ec05d63e | ||
|
|
da7a74ee58 | ||
|
|
72d08f60b2 | ||
|
|
4e6878972e | ||
|
|
f5efa5e93d | ||
|
|
179f765ca0 | ||
|
|
6a8f78ec23 | ||
|
|
f46e669eeb | ||
|
|
1c3188a3bb | ||
|
|
a7fe030557 | ||
|
|
dacadfc59e | ||
|
|
aa01855ac3 | ||
|
|
2d9b91eff5 | ||
|
|
d2c6c6e564 | ||
|
|
a11a4d1aee | ||
|
|
ad43a18f59 | ||
|
|
b1a9ff708c | ||
|
|
97a01b302f | ||
|
|
c22a73a98d | ||
|
|
bc9a7a0eb7 | ||
|
|
b35a737d97 | ||
|
|
760364d4c7 | ||
|
|
e4ff047c6e | ||
|
|
833219d5e5 | ||
|
|
eed1ab3ce3 | ||
|
|
c9a427bf8b | ||
|
|
6b4d7bde71 | ||
|
|
96442a3578 | ||
|
|
60e1dfb380 | ||
|
|
deaa150ab4 | ||
|
|
ca649a31a4 | ||
|
|
a2e514c10d | ||
|
|
0577a64ae3 | ||
|
|
1a69842871 | ||
|
|
992c6c71b0 | ||
|
|
bad0914e3c | ||
|
|
8495a234e8 | ||
|
|
3faa6577df | ||
|
|
f398d2a0d8 | ||
|
|
335ae82a3d | ||
|
|
4ac15880db | ||
|
|
fd5c2795b1 | ||
|
|
47c71422bc | ||
|
|
bfb7fd92b0 | ||
|
|
bf52430da8 | ||
|
|
7005b3ee86 | ||
|
|
8f2ea239c5 | ||
|
|
9ee2a8a98c | ||
|
|
6f0daf9d1b | ||
|
|
28ed424fa8 | ||
|
|
fe3e20b108 | ||
|
|
23f3b901e3 | ||
|
|
567608b3c4 | ||
|
|
4ff0f94d41 | ||
|
|
a56290489c | ||
|
|
aac4392f69 | ||
|
|
c130feefc5 | ||
|
|
474bcf5f05 | ||
|
|
cf24ada3f1 | ||
|
|
7b26bb7171 | ||
|
|
83d89ff05c | ||
|
|
7034bdcbf6 | ||
|
|
4c12da5418 | ||
|
|
8bf1d2bc1f | ||
|
|
900a99653f | ||
|
|
f33fcfa7b1 | ||
|
|
130148d475 | ||
|
|
021f87eef3 | ||
|
|
8ef8788152 | ||
|
|
041756829a | ||
|
|
89c7f52d84 | ||
|
|
c40b560d15 | ||
|
|
74f9391076 | ||
|
|
76dab68759 | ||
|
|
d405548825 | ||
|
|
b4c76f034f | ||
|
|
cda2402d01 | ||
|
|
2cf9ab2620 | ||
|
|
465f182493 | ||
|
|
23321a1075 | ||
|
|
ff2b9243e9 | ||
|
|
471fb7a83c | ||
|
|
0db5ae8390 | ||
|
|
e36f60085f | ||
|
|
3718fc36f0 | ||
|
|
71a41f6369 | ||
|
|
47a2f9a4a7 | ||
|
|
a6f0bc0490 | ||
|
|
cb7c37a836 | ||
|
|
e89eba08c4 | ||
|
|
d5d857983d | ||
|
|
9ab30dffd8 | ||
|
|
1e630c3c68 | ||
|
|
b2cd596401 | ||
|
|
ef6be9d436 | ||
|
|
9f6a9f9912 | ||
|
|
e4c37af7b7 | ||
|
|
353e90cf6d | ||
|
|
ecf7fb4bc4 | ||
|
|
e200a5ed78 | ||
|
|
5e02263ad1 | ||
|
|
a6af810274 | ||
|
|
d9d34735da | ||
|
|
087bc95f80 | ||
|
|
ff27f9832a | ||
|
|
2124e66219 | ||
|
|
9ae80b60b4 | ||
|
|
d701c4c3f9 | ||
|
|
b4cc5eea66 | ||
|
|
7cdf14c43b | ||
|
|
06d086725c | ||
|
|
a8e79d64c0 | ||
|
|
742c6fa5dd | ||
|
|
f4cfdc6647 | ||
|
|
43ae566053 | ||
|
|
063a6428f3 | ||
|
|
3e302d7c04 | ||
|
|
436ceabb9e | ||
|
|
186dc6db31 | ||
|
|
af4feba7d7 | ||
|
|
549aac15b7 | ||
|
|
06d8d92dbe | ||
|
|
6a8763d7ba | ||
|
|
521b97b7b7 | ||
|
|
58c8601067 | ||
|
|
36609376e8 | ||
|
|
32a1c8264e | ||
|
|
06754f4ef1 | ||
|
|
99d9b3bf94 | ||
|
|
ec71d20d37 | ||
|
|
2d1e88bb39 | ||
|
|
c9d30bb422 | ||
|
|
cd448082e3 | ||
|
|
46239dddac | ||
|
|
81177fda35 | ||
|
|
983d623d7f | ||
|
|
bdda8f4abf | ||
|
|
94fc804394 | ||
|
|
e00d8c09e7 | ||
|
|
70a40b4bdd | ||
|
|
f806a62f01 | ||
|
|
71a9281b8f | ||
|
|
a34747fbd5 | ||
|
|
6b0380199b | ||
|
|
39d2f90a84 | ||
|
|
7bff7651f3 | ||
|
|
44bd15d519 | ||
|
|
1ca93b03a0 | ||
|
|
3295142d81 | ||
|
|
f12fdc46dc | ||
|
|
fc01254fe6 | ||
|
|
8fb3368601 | ||
|
|
58facc2512 | ||
|
|
b43c2b308b | ||
|
|
1e89a0af56 | ||
|
|
acd3cbbf49 | ||
|
|
a806521745 | ||
|
|
0dddaf26e0 | ||
|
|
cdf63a005b | ||
|
|
ca422a0af3 | ||
|
|
a682371a91 | ||
|
|
26ef146526 | ||
|
|
936ee58abb | ||
|
|
71d8c208bc | ||
|
|
2200ffa88e | ||
|
|
4453316516 | ||
|
|
b947207571 | ||
|
|
25d29deae6 | ||
|
|
9abe6d6d71 | ||
|
|
77dbc0a37f | ||
|
|
659117512b | ||
|
|
b1dbbc6a69 | ||
|
|
424a1c626e | ||
|
|
522666191b | ||
|
|
78055ef794 | ||
|
|
0fe534c202 | ||
|
|
257179de31 | ||
|
|
65b57112b9 | ||
|
|
27f0b1d1f2 | ||
|
|
6e31476c45 | ||
|
|
bc7f0f3fb3 | ||
|
|
13eeb5164f | ||
|
|
fc756ed23d | ||
|
|
c150365462 | ||
|
|
58d209059e | ||
|
|
506179b517 | ||
|
|
f0f4eb75df | ||
|
|
6c1c025668 | ||
|
|
987032b384 | ||
|
|
d516cbf363 | ||
|
|
824274ac5e | ||
|
|
82b1c784f4 | ||
|
|
232512b860 | ||
|
|
223fa421c7 | ||
|
|
2e5e72bfcf | ||
|
|
9bdb986382 | ||
|
|
901ff30e11 | ||
|
|
5e04599212 | ||
|
|
d3c9b7ead3 | ||
|
|
361770c34b | ||
|
|
5168f3fa97 | ||
|
|
94d307e198 | ||
|
|
eba6236ad2 | ||
|
|
d0128bd989 | ||
|
|
fbd7c0ec36 | ||
|
|
55abac97ea | ||
|
|
740b94170e | ||
|
|
c6a1a09213 | ||
|
|
cd84d52398 | ||
|
|
cdbad1b397 | ||
|
|
67e227008a | ||
|
|
23cf43cac5 | ||
|
|
62a057dbfb | ||
|
|
f2ff9ae557 | ||
|
|
9ed4e46919 | ||
|
|
faa71bae40 | ||
|
|
bbd5d2cd6d | ||
|
|
221e135c07 | ||
|
|
956904c0b3 | ||
|
|
8590481022 | ||
|
|
2171d0139e | ||
|
|
71d6aca9f8 | ||
|
|
0125e279c0 | ||
|
|
b8e46ccf10 | ||
|
|
787fef1c03 | ||
|
|
98b7a6171f | ||
|
|
210f254f63 | ||
|
|
ecdccda1ce | ||
|
|
ed66ac91e0 | ||
|
|
e571165c15 | ||
|
|
1513664b5f | ||
|
|
0132d81c43 | ||
|
|
8d32da8b27 | ||
|
|
b5fbc8af86 | ||
|
|
d0166b5a5c | ||
|
|
ada77d6970 | ||
|
|
9f8758b242 | ||
|
|
5ca629ebea | ||
|
|
f9f3820652 | ||
|
|
08e61ecf19 | ||
|
|
d15f0cafce | ||
|
|
1b85253940 | ||
|
|
b329ff007e | ||
|
|
f6918d598a | ||
|
|
0cdfdd82d4 | ||
|
|
de3649dba4 | ||
|
|
9ba975ac44 | ||
|
|
2b0ea92da8 | ||
|
|
b79a1e973d | ||
|
|
1be4cf986d | ||
|
|
18c4226b90 | ||
|
|
07a5ba6857 | ||
|
|
6252d02498 | ||
|
|
11cf8c5397 | ||
|
|
1f3f4a4c85 | ||
|
|
5bfe5967db | ||
|
|
476fa25a12 | ||
|
|
792bd20fa2 | ||
|
|
26f3cd064e | ||
|
|
0556a84cbc | ||
|
|
090871625a | ||
|
|
12dedb7cff | ||
|
|
d4187e93b2 | ||
|
|
1beb1aafd8 | ||
|
|
67c4703bab | ||
|
|
d850c9c6e3 | ||
|
|
38e07b0859 | ||
|
|
ea10785160 | ||
|
|
16803b9f17 | ||
|
|
b9a0cf3f76 | ||
|
|
71ff6b14da | ||
|
|
a98b3c7e85 | ||
|
|
7259c25ece | ||
|
|
5e7154530b | ||
|
|
d501cc0a23 | ||
|
|
45606285ec | ||
|
|
a5e860a60f | ||
|
|
d93333f9ef | ||
|
|
3bd68b630a | ||
|
|
97c93a0858 | ||
|
|
8b15fe0d6a | ||
|
|
2d22a5f5b9 | ||
|
|
be63fbaada | ||
|
|
dc6b338266 | ||
|
|
9e36971151 | ||
|
|
9dc08d16b6 | ||
|
|
182a5412a5 | ||
|
|
cb15c79e4b | ||
|
|
06e6e81779 | ||
|
|
938b833954 | ||
|
|
596f069e46 | ||
|
|
e16a7f06d6 | ||
|
|
2947f2c2ff | ||
|
|
0d33039b72 | ||
|
|
682f8227fd | ||
|
|
dc1675073d | ||
|
|
d71f4eb802 | ||
|
|
e55756469d | ||
|
|
3764b705a8 | ||
|
|
1e4ef9c381 | ||
|
|
8188d8256a | ||
|
|
5fb2fcb059 | ||
|
|
0bb2f677b2 | ||
|
|
4d324de343 | ||
|
|
8e2972edae | ||
|
|
550ff83781 | ||
|
|
db793810eb | ||
|
|
1fb24c5705 | ||
|
|
cbbdfce5cd | ||
|
|
8576e377fa | ||
|
|
0d500f443f | ||
|
|
bed6dacff2 | ||
|
|
8643c6b260 | ||
|
|
71e529ebe9 | ||
|
|
fc951b964f | ||
|
|
900d3d6b71 | ||
|
|
2b3b5e02f5 | ||
|
|
b1b75dcad2 | ||
|
|
b558b1c6b4 | ||
|
|
9e58b97362 | ||
|
|
1f4f4f1a5f | ||
|
|
bc705b5563 | ||
|
|
677850e18a | ||
|
|
1f2c3af660 | ||
|
|
667ffec667 | ||
|
|
9837c23daf | ||
|
|
ab3bef3d2f | ||
|
|
58cb710d38 | ||
|
|
afbb340f8d | ||
|
|
f378741152 | ||
|
|
9f88bda8e5 | ||
|
|
33ebb1593f | ||
|
|
b0b91bd002 | ||
|
|
77518cf1f5 | ||
|
|
8b329ed602 | ||
|
|
0b27b21e75 | ||
|
|
d7da55c823 | ||
|
|
e6c15e2f73 | ||
|
|
c3dbd77c17 | ||
|
|
f7901711a9 | ||
|
|
ec8fee0a75 | ||
|
|
ca6ce3af09 | ||
|
|
65eaf0fc76 | ||
|
|
bfba8d10cf | ||
|
|
6cd89a5614 | ||
|
|
16163c7c5f | ||
|
|
0482fbed05 | ||
|
|
d0f1574893 | ||
|
|
e64167bb99 | ||
|
|
22098c5424 | ||
|
|
273c56aa0b | ||
|
|
a951361fa6 | ||
|
|
2795c3718b | ||
|
|
1a365bdefd | ||
|
|
d3db70baab | ||
|
|
20324ad88b | ||
|
|
80f34bdf3e | ||
|
|
f2dbdb95dc | ||
|
|
0e3893122d | ||
|
|
831ff6e3ae | ||
|
|
b62d17cbee | ||
|
|
b95d6cfca0 | ||
|
|
d0d1876783 | ||
|
|
df23bf21ea | ||
|
|
934561e551 | ||
|
|
de6c560027 | ||
|
|
9c582fccc8 | ||
|
|
cab5c26e3e | ||
|
|
cca6dda9e6 | ||
|
|
77aea23007 | ||
|
|
42c5403bbe | ||
|
|
b14dacd44d | ||
|
|
abd47ddcf7 | ||
|
|
8611e65fc6 | ||
|
|
8663fe39e3 | ||
|
|
4891213a88 | ||
|
|
828ea8e61a | ||
|
|
f6fae7c0b8 | ||
|
|
b4b446e770 | ||
|
|
9ff4fdaab8 | ||
|
|
d3bfbb0642 | ||
|
|
57ab0a05f7 | ||
|
|
296aee9757 | ||
|
|
3d8c408627 | ||
|
|
11cdb24558 | ||
|
|
589cc69498 | ||
|
|
6f17ab1f02 | ||
|
|
7cbbff727f | ||
|
|
daa07ed2d2 | ||
|
|
b3ced3bb40 | ||
|
|
20127e5bcd | ||
|
|
f7a5e462b7 | ||
|
|
728bc723c2 | ||
|
|
b1f75ec35b | ||
|
|
1709c778a6 | ||
|
|
769e110ffb | ||
|
|
a0808d2d4c | ||
|
|
59bd38ddc7 | ||
|
|
000ecb5669 | ||
|
|
8525f60488 | ||
|
|
24329faf5c | ||
|
|
4a72c6fdf9 | ||
|
|
8235c3048e | ||
|
|
209e9f0573 | ||
|
|
9455121647 | ||
|
|
fa7a11617e | ||
|
|
a6c62bc118 | ||
|
|
dbf4073da4 | ||
|
|
552ca12bc1 | ||
|
|
e13968eec1 | ||
|
|
2ce56c8581 | ||
|
|
8d6cc8c86a | ||
|
|
488719de1e | ||
|
|
8cb4011a44 | ||
|
|
9ff0bab873 | ||
|
|
3331738f2b | ||
|
|
e768ceea96 | ||
|
|
cb4215910c | ||
|
|
b9e014b8bd | ||
|
|
96f0743ce5 | ||
|
|
560766dfa0 | ||
|
|
a2bbccd3ea | ||
|
|
5570b804ba | ||
|
|
3ff1d4b68c | ||
|
|
d19d3c382c | ||
|
|
05a68a7506 | ||
|
|
9aacf4c780 | ||
|
|
0390dc14c5 | ||
|
|
1ee1ef836a | ||
|
|
bf1080ac5a | ||
|
|
ee4fdb9563 | ||
|
|
a179f2a895 | ||
|
|
b4c3a4b19f | ||
|
|
71e203f19c | ||
|
|
07283ba9ab | ||
|
|
decfb2c168 | ||
|
|
71778656da | ||
|
|
517d6e3e1a | ||
|
|
e11e9e7201 | ||
|
|
135b9336a4 | ||
|
|
e0d4d4abbd | ||
|
|
422b4fce7b | ||
|
|
e3a7226648 | ||
|
|
5b9fc86319 | ||
|
|
5afea2d3c7 | ||
|
|
5f942a6943 | ||
|
|
18075c5c51 | ||
|
|
a728225782 | ||
|
|
3e6ae26710 | ||
|
|
a8a4e442a8 | ||
|
|
c16e91734d | ||
|
|
bb9ad4b546 | ||
|
|
43045e5d4e | ||
|
|
63c7dbdb4d | ||
|
|
ef217bba90 | ||
|
|
ca9924c38f | ||
|
|
c3c47507e7 | ||
|
|
dc237c752a | ||
|
|
08892c71b2 | ||
|
|
026717b7c2 | ||
|
|
be06290f6c | ||
|
|
9ec55478c9 | ||
|
|
4172b4a2a6 | ||
|
|
59620c2217 | ||
|
|
c410c646b2 | ||
|
|
0b515996d7 | ||
|
|
8b9b8319a1 | ||
|
|
161cf14519 | ||
|
|
c6ac09e938 | ||
|
|
fde8f9d133 | ||
|
|
2bd222ca1c | ||
|
|
12228fe1fb | ||
|
|
c63b2592f1 | ||
|
|
e65980258c | ||
|
|
bd0a90d2dd | ||
|
|
33a7e92f4c | ||
|
|
51d1a1994d | ||
|
|
835745e485 | ||
|
|
bcb553d9f9 | ||
|
|
b73b8aae6a | ||
|
|
51792e31a8 | ||
|
|
636a391db3 | ||
|
|
57d5ed2f21 | ||
|
|
bbb1d1d908 | ||
|
|
c5d8f52f03 | ||
|
|
1b49e4a355 | ||
|
|
878cb589c3 | ||
|
|
53ce88d3d2 | ||
|
|
85e9bea9e7 | ||
|
|
7c7f88ebb5 | ||
|
|
cbd007b81a | ||
|
|
ac0438de42 | ||
|
|
b73699be8d | ||
|
|
bc87b6e955 | ||
|
|
f15155ddc9 | ||
|
|
37b556012e | ||
|
|
79ba3dd874 | ||
|
|
28795c3158 | ||
|
|
935d248b53 | ||
|
|
b2103afe30 | ||
|
|
fcbc4e420e | ||
|
|
19fcda877f | ||
|
|
48cd93ef93 | ||
|
|
80fd39826b | ||
|
|
50c7d1531b | ||
|
|
657c6f2b7d | ||
|
|
e7484fac09 | ||
|
|
613ec9c48c | ||
|
|
322050efd8 | ||
|
|
5242368343 | ||
|
|
564151e520 | ||
|
|
b40220cb73 | ||
|
|
2ebac74049 | ||
|
|
8ede63a960 | ||
|
|
38a0cc39e6 | ||
|
|
b482b61770 | ||
|
|
36a6f6e151 | ||
|
|
0c45883649 | ||
|
|
c243144009 | ||
|
|
4e2df006e7 | ||
|
|
02964d3bef | ||
|
|
c0e50aac48 | ||
|
|
6c0804ba4f | ||
|
|
708b13dd71 | ||
|
|
eb64e054b5 | ||
|
|
c42f7f930c | ||
|
|
44c1d7306d | ||
|
|
2413c22a51 | ||
|
|
31fefb4f86 | ||
|
|
745fd81aa1 | ||
|
|
f7bf1567c1 | ||
|
|
02021a09b1 | ||
|
|
6411d32228 | ||
|
|
56287e8094 | ||
|
|
62f70fd628 | ||
|
|
dcca2c5821 | ||
|
|
d22f2296c2 | ||
|
|
2e0ea5d085 | ||
|
|
cb4526e8e2 | ||
|
|
fc3132cd77 | ||
|
|
e474db33ec | ||
|
|
6274d2b250 | ||
|
|
d4bfdaa29e | ||
|
|
3b7f5f5ce0 | ||
|
|
496e2f1840 | ||
|
|
98f3c055d7 | ||
|
|
7df36ce8b4 | ||
|
|
5deaca45c2 | ||
|
|
e790757855 | ||
|
|
46b2c6494f | ||
|
|
c4216a4075 | ||
|
|
375412aa42 | ||
|
|
895ac56eb3 | ||
|
|
c593388ec6 | ||
|
|
1c6960fe44 | ||
|
|
e7ac2ffd6c | ||
|
|
df35e54fba | ||
|
|
15f757ae04 | ||
|
|
b7dc15099c | ||
|
|
dc33c67f48 | ||
|
|
89fb517fd1 | ||
|
|
51eb94dbe9 | ||
|
|
03747f618f | ||
|
|
8154322448 | ||
|
|
7531ae2749 | ||
|
|
32515172d3 | ||
|
|
3b500ecf69 | ||
|
|
b93dd4751d | ||
|
|
d651f8db34 | ||
|
|
3f8f7d21d0 | ||
|
|
824341e396 | ||
|
|
a972708d69 | ||
|
|
47b305c83b | ||
|
|
2ec3da18f2 | ||
|
|
70aea9ac0c | ||
|
|
38270bf4e2 | ||
|
|
05d58ca0da | ||
|
|
91aab54b43 | ||
|
|
25d552c09e | ||
|
|
a1d51502c4 | ||
|
|
883d1dfa19 | ||
|
|
f94c48b27c | ||
|
|
0734547aec | ||
|
|
8ab87d9844 | ||
|
|
21b3b85e6e | ||
|
|
45ccac3bc4 | ||
|
|
0b95b0b94b | ||
|
|
501b370dc0 | ||
|
|
2058a4b639 | ||
|
|
266823a81e | ||
|
|
6cd5713baa | ||
|
|
e9038de819 | ||
|
|
9129b681dc | ||
|
|
1f2b602638 | ||
|
|
87d9de1009 | ||
|
|
81a6db2190 | ||
|
|
dbd335fd3b | ||
|
|
84fc6e7a7a | ||
|
|
f851f10ee1 | ||
|
|
0d92d9f9bd | ||
|
|
73fce52df1 | ||
|
|
14223d239a | ||
|
|
a3daa7b257 | ||
|
|
a70f943462 | ||
|
|
a717260574 | ||
|
|
90a4898dbd | ||
|
|
4543d9e975 | ||
|
|
2aedd20007 | ||
|
|
822e1cbfb5 | ||
|
|
0ec082669d | ||
|
|
5315eeb26b | ||
|
|
32bd5a4cca | ||
|
|
e4ec774d16 | ||
|
|
b1ce21ad77 | ||
|
|
9ab5e86c81 | ||
|
|
ea3442ad27 | ||
|
|
e1af02a642 | ||
|
|
fe0c4e4f92 | ||
|
|
5e58fdf821 | ||
|
|
01537c03b1 | ||
|
|
b78f4d13c1 | ||
|
|
ba68243dc7 | ||
|
|
b742971d9b | ||
|
|
6492cfb430 | ||
|
|
c229adcbb9 | ||
|
|
abb08a4589 | ||
|
|
5ccc124ad4 | ||
|
|
db22fea0d1 | ||
|
|
7ebd12ec3d | ||
|
|
ac0e57726f | ||
|
|
e3200b1481 | ||
|
|
5492935c32 | ||
|
|
2a67d80057 | ||
|
|
7956a75344 | ||
|
|
cfa82e5086 | ||
|
|
60291a93c2 | ||
|
|
51fec1c5a0 | ||
|
|
5b8c5e2fd7 | ||
|
|
5a0fd6ee08 | ||
|
|
d7d3810874 | ||
|
|
f0819c339c | ||
|
|
adcdca6f2e | ||
|
|
efd7d1a4a0 | ||
|
|
fc3fa137ac | ||
|
|
61e901e07b | ||
|
|
d5dee106d1 | ||
|
|
00518e1a60 | ||
|
|
129d622015 | ||
|
|
4423cbfcf3 | ||
|
|
7f0d845dd0 | ||
|
|
bba1c894c5 | ||
|
|
6c197a4a8c | ||
|
|
4ceae8ec31 | ||
|
|
d257f903cc | ||
|
|
69742dd785 | ||
|
|
92161eae07 | ||
|
|
70d5099902 | ||
|
|
de80f4e262 | ||
|
|
0f0b8d4528 | ||
|
|
e34301fb2f | ||
|
|
a140c1ddc1 | ||
|
|
b472c615fb | ||
|
|
d41f33775e | ||
|
|
c27d60e2b0 | ||
|
|
77fcaf4fca | ||
|
|
206dc66f7c | ||
|
|
2d267fc50a | ||
|
|
5cd5f00df7 | ||
|
|
6a80869861 | ||
|
|
fb113514ae | ||
|
|
91740048c2 | ||
|
|
ff2e206229 | ||
|
|
5f1f82257b | ||
|
|
3df0fab793 | ||
|
|
7e7fa62c24 | ||
|
|
6220c00dcb | ||
|
|
59a3d58c0f | ||
|
|
d8fb19c26e | ||
|
|
b0530325c5 | ||
|
|
734a86a248 | ||
|
|
a12d447d95 | ||
|
|
e9578d9aa0 | ||
|
|
5fef185a30 | ||
|
|
ee2b2b2c3a | ||
|
|
45d232e401 | ||
|
|
9a4d56e4e1 | ||
|
|
63018439c8 | ||
|
|
b5fef2ecb9 | ||
|
|
fd3ece31c7 | ||
|
|
7aa8e3d60d | ||
|
|
9d71b39b31 | ||
|
|
7cb09a0e0b | ||
|
|
fa47448ddc | ||
|
|
be7ae3d151 | ||
|
|
fcb3c11203 | ||
|
|
c63002e145 | ||
|
|
7758079efa | ||
|
|
9e43cc30a7 | ||
|
|
40eaf15538 | ||
|
|
a6228b43f3 | ||
|
|
b5fcc90da2 | ||
|
|
c66e80fdaf | ||
|
|
7853e1990f | ||
|
|
9d52a335c3 | ||
|
|
8597784bc6 | ||
|
|
557b9ef71d | ||
|
|
c7791a478a | ||
|
|
d29a20727b | ||
|
|
a14a2f6c96 | ||
|
|
cc402e35a1 | ||
|
|
2813c30536 | ||
|
|
8bd0bdf5b2 | ||
|
|
26a99443d7 | ||
|
|
6d5aa77dee | ||
|
|
5fa7bea885 | ||
|
|
62fb85a94b | ||
|
|
c840e3485e | ||
|
|
04c72d51fd | ||
|
|
eae1250cac | ||
|
|
634801431d | ||
|
|
e9a884ab39 | ||
|
|
40fc1511d0 | ||
|
|
8642723c77 | ||
|
|
15ac97e41a | ||
|
|
8202ae7cf6 | ||
|
|
1b459460dc | ||
|
|
bdf7df9ecd | ||
|
|
7e55c6a79d | ||
|
|
183570aaa5 | ||
|
|
de1d66d4dd | ||
|
|
0b27e57ad7 | ||
|
|
182bbd43c5 | ||
|
|
cdf4d6c5fd | ||
|
|
86db74c394 | ||
|
|
856e63794b | ||
|
|
c29a57445a | ||
|
|
4aba90ad3f | ||
|
|
4f2b6d4cd7 | ||
|
|
92067fa3f3 | ||
|
|
c26ea4ceeb | ||
|
|
35ccbff5b9 | ||
|
|
1a265a5176 | ||
|
|
ef2d243fa8 | ||
|
|
c2b8fa59a6 | ||
|
|
a85f9e39bd | ||
|
|
a13f8828fb | ||
|
|
7d391b8465 | ||
|
|
dbfa7cc4eb | ||
|
|
66e99df303 | ||
|
|
77ecf64443 | ||
|
|
f7060804b2 | ||
|
|
a44a1269c0 | ||
|
|
ac6fc37c7d | ||
|
|
9472d65af9 | ||
|
|
1b4c07f229 | ||
|
|
a645058ae1 | ||
|
|
edec6defbb | ||
|
|
27b3a3ddef | ||
|
|
da0903b8a6 | ||
|
|
a49a3b45e5 | ||
|
|
b9225fb153 | ||
|
|
656b7f0948 | ||
|
|
08b249ee09 | ||
|
|
5d76ebfe6e | ||
|
|
0d53b12ade | ||
|
|
f403e12a2a | ||
|
|
5abce26309 | ||
|
|
e73cb0958f | ||
|
|
70070e2f1c | ||
|
|
2685f9adab | ||
|
|
c43e74eabd | ||
|
|
b0d3306209 | ||
|
|
4aaabae109 | ||
|
|
b8188f999e | ||
|
|
4dc5ceb9b1 | ||
|
|
4f8e5053f7 | ||
|
|
3d97ce99e1 | ||
|
|
8620412b3a | ||
|
|
a6d07d89d0 | ||
|
|
a63efcefd6 | ||
|
|
bce9207161 | ||
|
|
12670dedbe | ||
|
|
40393f9548 | ||
|
|
94cae5f015 | ||
|
|
8353227f9d | ||
|
|
5c1d69b934 | ||
|
|
fb04b58b57 | ||
|
|
2bb14bba2a | ||
|
|
91195eb21b | ||
|
|
3b8d6dd3c8 | ||
|
|
ff2ab2da8d | ||
|
|
85aed457b2 | ||
|
|
d624d1d5b6 | ||
|
|
6c6a1049ea | ||
|
|
f380889d98 | ||
|
|
f61df0e126 | ||
|
|
ffca12123f | ||
|
|
1077ca3753 | ||
|
|
c7189dbceb | ||
|
|
f2361c49b4 | ||
|
|
f84cbb66c3 | ||
|
|
e45f254d19 | ||
|
|
b6cd3c0bae | ||
|
|
4a98724a35 | ||
|
|
4680fa5ae9 | ||
|
|
458f4e2bdc | ||
|
|
3357fd81c7 | ||
|
|
3ebe277303 | ||
|
|
29c57dce0f | ||
|
|
27a9330638 | ||
|
|
4b42b1f55d | ||
|
|
db761395e5 | ||
|
|
249d73e270 | ||
|
|
5d359afedb | ||
|
|
5e8e37e6a2 | ||
|
|
a74df6f04f | ||
|
|
10991d5472 | ||
|
|
b3206fe1db | ||
|
|
70391ea055 | ||
|
|
5b69155d49 | ||
|
|
941bb8adca | ||
|
|
b5eb014084 | ||
|
|
ee4b9339a7 | ||
|
|
3acfe19499 | ||
|
|
9bac23b38f | ||
|
|
b028258cbd | ||
|
|
4d442159cb | ||
|
|
181a91ccf6 | ||
|
|
1c6f2e9d10 | ||
|
|
244fe3b116 | ||
|
|
9ee7391918 | ||
|
|
2eadc3ace6 | ||
|
|
786b29c18d | ||
|
|
315f787d20 | ||
|
|
0347907044 | ||
|
|
f2ae281195 | ||
|
|
a4f76d59b0 | ||
|
|
52a3e04eae | ||
|
|
390abb00df | ||
|
|
02c50e4b17 | ||
|
|
8c8a78c0ab | ||
|
|
fb75cde710 | ||
|
|
fc855dccff | ||
|
|
3d57def676 | ||
|
|
74d2da8857 | ||
|
|
8cfd721ef6 | ||
|
|
d4e10f32e7 | ||
|
|
5a7cff491d | ||
|
|
392ae695d0 | ||
|
|
b39effc067 | ||
|
|
908f4f01cf | ||
|
|
8baab13192 | ||
|
|
abb38d3e49 | ||
|
|
d0016e390a | ||
|
|
c80012e367 | ||
|
|
19fc60a1d8 | ||
|
|
487c9e96ce | ||
|
|
cd337cb164 | ||
|
|
5c15747d62 | ||
|
|
7f11e6946b | ||
|
|
8fa77691d0 | ||
|
|
894e5910c3 | ||
|
|
54f33a72c4 | ||
|
|
566f90ff30 | ||
|
|
debc59744f | ||
|
|
33c6ac813c | ||
|
|
04875d07c5 | ||
|
|
39eb594e12 | ||
|
|
2561182126 | ||
|
|
a68ab27bac | ||
|
|
c27acb0e90 | ||
|
|
875d1ab952 | ||
|
|
3496480254 | ||
|
|
2ca79ab3b9 | ||
|
|
51ce7b657c | ||
|
|
67a34dcc78 | ||
|
|
81d27ece54 | ||
|
|
f3a2e54e61 | ||
|
|
1894ed72e3 | ||
|
|
64bf7d541e | ||
|
|
8beba13430 | ||
|
|
6379869d41 | ||
|
|
5a666a28ef | ||
|
|
3c80053010 | ||
|
|
7fd4941923 | ||
|
|
b42e600285 | ||
|
|
df8859d49e | ||
|
|
d62d006398 | ||
|
|
dadf1bdcc1 | ||
|
|
da961b7722 | ||
|
|
087326ed32 | ||
|
|
fc9f66e3e2 | ||
|
|
cb25e0dcb3 | ||
|
|
88da458c2b | ||
|
|
705b3aa74e | ||
|
|
f35bfa45db | ||
|
|
cc59037fbc | ||
|
|
1c442128dd | ||
|
|
d70d8d34dc | ||
|
|
2c972995d3 | ||
|
|
794f6239bb | ||
|
|
5f498c3bb1 | ||
|
|
8efce7430f | ||
|
|
fa3bf93464 | ||
|
|
ff1f0986cf | ||
|
|
a1601a0c1f | ||
|
|
2f457c2721 | ||
|
|
02c9d0d387 | ||
|
|
9b002fe568 | ||
|
|
73ec5df88d | ||
|
|
82e0635995 | ||
|
|
da0ff7be27 | ||
|
|
569260b396 | ||
|
|
bbce0afbf4 | ||
|
|
33022d82c4 | ||
|
|
a7c29fa317 | ||
|
|
8974944044 | ||
|
|
60c86a45da | ||
|
|
92883f313a | ||
|
|
ce4524e2bb | ||
|
|
fdf4242a6c | ||
|
|
e44c603ba7 | ||
|
|
1f30714e17 | ||
|
|
36f32f518f | ||
|
|
bdbd02fa0b | ||
|
|
0a1e018144 | ||
|
|
601649e028 | ||
|
|
7c17dc64c9 | ||
|
|
647f04b6f0 | ||
|
|
c2102c38f3 | ||
|
|
6c82e47d32 | ||
|
|
b53529614e | ||
|
|
2a25c201a7 | ||
|
|
8f3d5047fc | ||
|
|
6a08b5b71b | ||
|
|
c08715614a | ||
|
|
ea2b130b57 | ||
|
|
daa3b25822 | ||
|
|
0184e8de2f | ||
|
|
eec59252f6 | ||
|
|
2b7f8fb1c9 | ||
|
|
345a37d024 | ||
|
|
5f04211c58 | ||
|
|
80b679e9dc | ||
|
|
e9ecf39d54 | ||
|
|
c5a022958c | ||
|
|
97abbafbe9 | ||
|
|
776b0367a5 | ||
|
|
c6822fc4f5 | ||
|
|
a2f10b5416 | ||
|
|
4ea7ce7138 | ||
|
|
ab9842b599 | ||
|
|
7bba292f46 | ||
|
|
867bbd5326 | ||
|
|
2690f26300 | ||
|
|
b514c81015 | ||
|
|
cd75d5acd3 | ||
|
|
b9a60f598c | ||
|
|
7b39578461 | ||
|
|
8934c29617 | ||
|
|
dbaed5c8ed | ||
|
|
5a091d55a6 | ||
|
|
a28d7ecfab | ||
|
|
7dea433f52 | ||
|
|
80a2ffdead | ||
|
|
e4b5d937d7 | ||
|
|
5806f816b8 | ||
|
|
385928c6e5 | ||
|
|
3e1654356d | ||
|
|
def4d596dc | ||
|
|
a239039a89 | ||
|
|
1a71265354 | ||
|
|
9a3a3b0868 | ||
|
|
b0a109bd0d | ||
|
|
525d10c0ae | ||
|
|
8de65d48f3 | ||
|
|
a5f21c764c | ||
|
|
1e4e18e51d | ||
|
|
281921ec59 | ||
|
|
c10efcbf4c | ||
|
|
661ab24d6f | ||
|
|
4bf33f5a0a | ||
|
|
b256e086c7 | ||
|
|
a9470ae959 | ||
|
|
100018d6bf | ||
|
|
7719513c72 | ||
|
|
970703671d | ||
|
|
6d3a4a391c | ||
|
|
9838c6a05c | ||
|
|
5744b1ae98 | ||
|
|
879af8744d | ||
|
|
640f941180 | ||
|
|
a48d8b8f6a | ||
|
|
20d92bf36b | ||
|
|
7f2ab5d629 | ||
|
|
bb46b474c3 | ||
|
|
5a3e8836e0 | ||
|
|
e100c4ce7f | ||
|
|
32b3db80d8 | ||
|
|
7ac24e69c4 | ||
|
|
80f2a5476e | ||
|
|
d27237832e | ||
|
|
73a3ce9889 | ||
|
|
ff66b8ec01 | ||
|
|
d632084c58 | ||
|
|
4257ff3e67 | ||
|
|
72ca0a6ef7 | ||
|
|
5b361a6a2e | ||
|
|
40d3a69b1c | ||
|
|
0cc618e1b2 | ||
|
|
0ee04ada31 | ||
|
|
807b1c64dd | ||
|
|
690aad123c | ||
|
|
73b6a3159f | ||
|
|
73e8a18d5a | ||
|
|
e613dda536 | ||
|
|
2621b90d3b | ||
|
|
9e95736b48 | ||
|
|
de4ca8e55c | ||
|
|
f4247e0361 | ||
|
|
d9df7b66f5 | ||
|
|
c5feb5bdc9 | ||
|
|
ee170d2f51 | ||
|
|
eea6d07613 | ||
|
|
4a9a26d470 | ||
|
|
f949487a75 | ||
|
|
d7572c5772 | ||
|
|
74e3bbb83b | ||
|
|
adaa4cade5 | ||
|
|
09e670bce4 | ||
|
|
d6b601968d | ||
|
|
f07db641d4 | ||
|
|
1ffdd53629 | ||
|
|
97f91e734a | ||
|
|
4eee13ac02 | ||
|
|
5869022a28 | ||
|
|
19e77590f3 | ||
|
|
bc790275aa | ||
|
|
1c35cd9d65 | ||
|
|
d6dd8da81e | ||
|
|
d55b23c482 | ||
|
|
f95f83c85b | ||
|
|
f0fa67d16d | ||
|
|
89756b7c9e | ||
|
|
5f9693cb34 | ||
|
|
2856f3af8c | ||
|
|
e7b1db8b09 | ||
|
|
48c3a84b85 | ||
|
|
eca3705794 | ||
|
|
74fd17d7ac | ||
|
|
35cbf0ebb4 | ||
|
|
2eb8b8e2b2 | ||
|
|
883596d1d7 | ||
|
|
698487377b | ||
|
|
c3d826df8c | ||
|
|
d5536ed246 | ||
|
|
df077f8ef6 | ||
|
|
4293a098e3 | ||
|
|
cf07260186 | ||
|
|
9ad5bd477b | ||
|
|
1d2c1dbc6f | ||
|
|
8c44c5b79a | ||
|
|
0c84eb3dd0 | ||
|
|
869792c09e | ||
|
|
09ab158d66 | ||
|
|
f539a8ccda | ||
|
|
171f049607 | ||
|
|
43e47e6249 | ||
|
|
afbfe72489 | ||
|
|
59d042c9a7 | ||
|
|
38a613de45 | ||
|
|
1c27ebc1e4 | ||
|
|
6f1d8a99e7 | ||
|
|
8c9e5b4963 | ||
|
|
3c3aeac93c | ||
|
|
846c2761f6 | ||
|
|
d03eabe4d5 | ||
|
|
cad9be6e74 | ||
|
|
dbb166e94f | ||
|
|
6b92922ee5 | ||
|
|
479431b283 | ||
|
|
2ab1a27f8b | ||
|
|
8470e61e3f | ||
|
|
6c6c8c86d8 | ||
|
|
efab6ee229 | ||
|
|
72a1173615 | ||
|
|
1dfa3a64a7 | ||
|
|
7b36396570 | ||
|
|
c1a8470dcf | ||
|
|
ba0d9ac834 | ||
|
|
56d0feab12 | ||
|
|
0674737796 | ||
|
|
58b632b6c6 | ||
|
|
43f3e13491 | ||
|
|
7b69060776 | ||
|
|
75f6cc7f0f | ||
|
|
8ef8200363 | ||
|
|
8b31c38229 | ||
|
|
651591a063 | ||
|
|
c86b3c972b | ||
|
|
7529297151 | ||
|
|
2c411e343d | ||
|
|
e9d8f6aebd | ||
|
|
d144582f1c | ||
|
|
2d3e703979 | ||
|
|
af440ffffa | ||
|
|
e129b2df57 | ||
|
|
09f2b36920 | ||
|
|
37af295873 | ||
|
|
52d21e94d3 | ||
|
|
acd80cc05e | ||
|
|
de48464661 | ||
|
|
623cac6220 | ||
|
|
ad558b4984 | ||
|
|
ae0ba59f67 | ||
|
|
fd28a8b427 | ||
|
|
b390e5de98 | ||
|
|
82402abe43 | ||
|
|
78da7ddb55 | ||
|
|
1dd48743c2 | ||
|
|
015417d640 | ||
|
|
94de00b14c | ||
|
|
4d237c4328 | ||
|
|
b7f721e869 | ||
|
|
49ba555fc0 | ||
|
|
cd1b25ec2b | ||
|
|
109725fafe | ||
|
|
9c7b61070b | ||
|
|
8b5a1fef51 | ||
|
|
72f8dd5b3a | ||
|
|
1d3a922a7b | ||
|
|
ab2b145556 | ||
|
|
8960ff5a4d | ||
|
|
06b41b1b5a | ||
|
|
4277ac65a4 | ||
|
|
6ed815f1ac | ||
|
|
4ebfa6a3d0 | ||
|
|
529f75467b | ||
|
|
062895c7ca | ||
|
|
7b174ac498 | ||
|
|
beb8f627ee | ||
|
|
1badbaa182 | ||
|
|
75f2930f53 | ||
|
|
60b746e4dd | ||
|
|
dbef9af0df | ||
|
|
2a5cdf49ad | ||
|
|
0bb5432223 | ||
|
|
f565a50e90 | ||
|
|
0a840228b2 | ||
|
|
37c1964991 | ||
|
|
f3cd5b06fa | ||
|
|
c735ad5110 | ||
|
|
51b27cb002 | ||
|
|
0406f1df01 | ||
|
|
a72401a529 | ||
|
|
406c4d20cf | ||
|
|
49ef9ae85d | ||
|
|
d65eacea41 | ||
|
|
347904297e | ||
|
|
404aeb026d | ||
|
|
29df51a4b0 | ||
|
|
397cde2be2 | ||
|
|
a848283d59 | ||
|
|
80b4582e81 | ||
|
|
9d5c7d3317 | ||
|
|
b860741ab8 | ||
|
|
792825bdaa | ||
|
|
ad2371dc9a | ||
|
|
dfb771a51e | ||
|
|
14a0dbbd5c | ||
|
|
bb1c63cc92 | ||
|
|
38ca26e6f3 | ||
|
|
285d5688f5 | ||
|
|
26cdfc2279 | ||
|
|
d915dfc941 | ||
|
|
d29bd65f97 | ||
|
|
81d378498e | ||
|
|
d32630c759 | ||
|
|
b8d7ec0723 | ||
|
|
207c5430c1 | ||
|
|
b922274b61 | ||
|
|
863c0e5eb7 | ||
|
|
46f9956791 | ||
|
|
879a6f2552 | ||
|
|
5e3d237c99 | ||
|
|
1eb83e4eb0 | ||
|
|
194c0e6708 | ||
|
|
a87d38c61f | ||
|
|
ed0e5bbf9b | ||
|
|
2249b623e6 | ||
|
|
854ca5f5d4 | ||
|
|
a0a8029c36 | ||
|
|
e7eec8e4f1 | ||
|
|
a354c1984b | ||
|
|
34799c397c | ||
|
|
2c88dddc1e | ||
|
|
64b0216ba9 | ||
|
|
f950520475 | ||
|
|
60f3de2a91 | ||
|
|
06e13483bd | ||
|
|
f00cbe89bc | ||
|
|
e450f5744b | ||
|
|
255242eca5 | ||
|
|
cbeab4dd55 | ||
|
|
6b8506c986 | ||
|
|
d5d5647b7c | ||
|
|
1a76de1ca3 | ||
|
|
1913109623 | ||
|
|
e76b4395a7 | ||
|
|
6670156397 | ||
|
|
37b7a77b70 | ||
|
|
ddb5a007a5 | ||
|
|
8568df4552 | ||
|
|
493a5f715c | ||
|
|
a61b27992e | ||
|
|
798eec7aa8 | ||
|
|
0d29603e2b | ||
|
|
48882220d6 | ||
|
|
b4ad292ec5 | ||
|
|
b59a14f6b7 | ||
|
|
80ed385a41 | ||
|
|
04cd67b98b | ||
|
|
68eded2c0c | ||
|
|
389a0d3afa | ||
|
|
5a3e4a28fe | ||
|
|
66b5629a31 | ||
|
|
eae77eb236 | ||
|
|
5f44ec8a0d | ||
|
|
9d8c62de6b | ||
|
|
3229fd8d28 | ||
|
|
fdee789637 | ||
|
|
c762dda1b1 | ||
|
|
c5c8b902c4 | ||
|
|
ee255a5042 | ||
|
|
3952965632 | ||
|
|
85db706bbe | ||
|
|
ea570442c6 | ||
|
|
9c109b803d | ||
|
|
86f77f8064 | ||
|
|
81c33d65e4 | ||
|
|
a1cf822141 | ||
|
|
ce48a9697a | ||
|
|
9b22c4b23c | ||
|
|
6283b0460a | ||
|
|
4fe977fa47 | ||
|
|
f188e55692 | ||
|
|
f5487ed932 | ||
|
|
c69b25ff0d | ||
|
|
b608af640f | ||
|
|
315f1ff3bc | ||
|
|
b6c2ac194b | ||
|
|
00570d2089 | ||
|
|
56375b16fe | ||
|
|
447a7b684c | ||
|
|
82379481dd | ||
|
|
06f9e28170 | ||
|
|
d89b6f814b | ||
|
|
fad69356c1 | ||
|
|
2285c6e430 | ||
|
|
c1b9b727e6 | ||
|
|
a95714710b | ||
|
|
82268b58e2 | ||
|
|
0dd7e71fd1 | ||
|
|
63f1d2905f | ||
|
|
ea9b409a04 | ||
|
|
8957a8421d | ||
|
|
7c171081c6 | ||
|
|
e4520e9e16 | ||
|
|
336c373dd0 | ||
|
|
fc721f31c5 | ||
|
|
062ed9f7b8 | ||
|
|
59a915cdac | ||
|
|
191f7d2152 | ||
|
|
a76e9c2c1f | ||
|
|
9d616459b7 | ||
|
|
82fa42d182 | ||
|
|
0c36aaa5ff | ||
|
|
a9761464a0 | ||
|
|
355d02faa3 | ||
|
|
1052f37d02 | ||
|
|
92b023599b | ||
|
|
0c0dc946d8 | ||
|
|
9301edaee8 | ||
|
|
cf3136781d | ||
|
|
d17368a9d2 | ||
|
|
acfdef0c19 | ||
|
|
1f4c7239d7 | ||
|
|
2aa0dbd93d | ||
|
|
a9135280ba | ||
|
|
0352ed79fa | ||
|
|
87454c9b10 | ||
|
|
1afec3aa95 | ||
|
|
a7a3334c9a | ||
|
|
dc1f9bb252 | ||
|
|
b2cbb8c8d0 | ||
|
|
399de15792 | ||
|
|
9ef30625a6 | ||
|
|
9b870e64d2 | ||
|
|
c90a93661b | ||
|
|
d8349764ed | ||
|
|
232740fc2e | ||
|
|
88b5810d8e | ||
|
|
3fa528224f | ||
|
|
edc1f734b7 | ||
|
|
49f4ced8e0 | ||
|
|
7bc0a6d140 | ||
|
|
968a347664 | ||
|
|
1740b16a0f | ||
|
|
be5a71ce47 | ||
|
|
2d195e9584 | ||
|
|
b975489ddd | ||
|
|
5cefa5f2c4 | ||
|
|
4da9e64737 | ||
|
|
37f2b1abe2 | ||
|
|
6d729d27cd | ||
|
|
ec40cbc2ed | ||
|
|
0575f1710d | ||
|
|
15823e6fe8 | ||
|
|
7dbde008af | ||
|
|
d8ebd647a2 | ||
|
|
ece0d7fabe | ||
|
|
679a712e16 | ||
|
|
18ad9e22f5 | ||
|
|
152029c85b | ||
|
|
e91de667e0 | ||
|
|
7f21b8263b | ||
|
|
f65acc9f95 | ||
|
|
6a61bacd60 | ||
|
|
fb9489f470 | ||
|
|
87da19caa3 | ||
|
|
378f6fe485 | ||
|
|
65a8886e61 | ||
|
|
8fdb259270 | ||
|
|
98b0b46dda | ||
|
|
861fb9e3d5 | ||
|
|
644bcee14e | ||
|
|
933d9e92d1 | ||
|
|
9fb03a25f6 | ||
|
|
0b1f7827fc | ||
|
|
49f21e2c9d | ||
|
|
990c0e07cf | ||
|
|
745459e69f | ||
|
|
115a6cf5d7 | ||
|
|
39aafbbc61 | ||
|
|
93ddc9ce99 | ||
|
|
3d877eed13 | ||
|
|
308d612c05 | ||
|
|
9b75f0428d | ||
|
|
e6858659fb | ||
|
|
815058ffcd | ||
|
|
915b540576 | ||
|
|
5b06d6925c | ||
|
|
ef875fa720 | ||
|
|
994a7d044f | ||
|
|
80cd7f39b4 | ||
|
|
93bf45cde6 | ||
|
|
b4adc064a0 | ||
|
|
7e81d0bcbb | ||
|
|
33b59f091e | ||
|
|
ea3dc1f2f4 | ||
|
|
5d3e68a6a5 | ||
|
|
64f2ec3ffe | ||
|
|
c80014ec7d | ||
|
|
6515720d55 | ||
|
|
605c5cbfd8 | ||
|
|
77e97d1a89 | ||
|
|
f17d959770 | ||
|
|
22f1d2f642 | ||
|
|
7d3907fa0e | ||
|
|
9588fe8d94 | ||
|
|
3b3ffdb8d1 | ||
|
|
cdd7e6931a | ||
|
|
4c3df012a6 | ||
|
|
b0eaf93331 | ||
|
|
55c03279ca | ||
|
|
c4f0753f5a | ||
|
|
a9bd25873e | ||
|
|
5ab6de8123 | ||
|
|
75deb9d678 | ||
|
|
b5ce0e0766 | ||
|
|
43817aef20 | ||
|
|
81a7a58299 | ||
|
|
4ae1c21b6f | ||
|
|
8ffa3e5d4c | ||
|
|
ac6ebe1f99 | ||
|
|
a5c07e7873 | ||
|
|
94c4f6008d | ||
|
|
615c296023 | ||
|
|
d227611ee8 | ||
|
|
acf00c723f | ||
|
|
adb3913daa | ||
|
|
faf1a44944 | ||
|
|
9f5cb9ffff | ||
|
|
068c653a2a | ||
|
|
b1c922bb75 | ||
|
|
4879fbc6d4 | ||
|
|
e7dc81eb38 | ||
|
|
c2fa08598e | ||
|
|
d23ca4a38e | ||
|
|
078b608582 | ||
|
|
a64457973f | ||
|
|
00ef13fe9f | ||
|
|
b4a7f2fdf6 | ||
|
|
a482bb7acc | ||
|
|
ce46eeac49 | ||
|
|
110dbf6cca | ||
|
|
c93de2dd6f | ||
|
|
be88f5152f | ||
|
|
efda5bab4d | ||
|
|
d491eb1af0 | ||
|
|
e249dbfc67 | ||
|
|
c994ae5798 | ||
|
|
cba61bd8fb | ||
|
|
a72440ee6b | ||
|
|
cd3ed40ff3 | ||
|
|
cf3ce5e31d | ||
|
|
bdcbc5e011 | ||
|
|
c2d3ce348f | ||
|
|
970d580e4b | ||
|
|
d2f9721576 | ||
|
|
8a39e5827b | ||
|
|
89c8b6a0a5 | ||
|
|
238f0a6108 | ||
|
|
19950569cb | ||
|
|
a19553dddd | ||
|
|
c383a5b120 | ||
|
|
dab7243ccd | ||
|
|
ccf15ab4a3 | ||
|
|
25a3ef2b3e | ||
|
|
9bdaae8d9f | ||
|
|
4115651998 | ||
|
|
58349082df | ||
|
|
aa75828296 | ||
|
|
10eaf6e278 | ||
|
|
04e22571e9 | ||
|
|
bc8b9e7c8b | ||
|
|
b6213654ef | ||
|
|
9ba17d5338 | ||
|
|
dde453744d | ||
|
|
a86273f213 | ||
|
|
2b312dfa6f | ||
|
|
800c7182c1 | ||
|
|
cbbd5faf24 | ||
|
|
bb9c8f04e2 | ||
|
|
50469903dc | ||
|
|
b8f6cf11d6 | ||
|
|
f0d4f76e0f | ||
|
|
05f0a12d16 | ||
|
|
a1cad730ad | ||
|
|
3e8c738496 | ||
|
|
940dd3e3c0 | ||
|
|
6de4e1a401 | ||
|
|
0a8747f600 | ||
|
|
68a5e7c8f7 | ||
|
|
c3d4bf5428 | ||
|
|
0cac0bc761 | ||
|
|
05427b7b3b | ||
|
|
9e73f9b5e0 | ||
|
|
5ec41bafbe | ||
|
|
cb67cc8c3d | ||
|
|
d35619805f | ||
|
|
cb26758d53 | ||
|
|
9783674890 | ||
|
|
270eeda3e2 | ||
|
|
24d3d064bb | ||
|
|
e8eec80696 | ||
|
|
c366504868 | ||
|
|
c7b54856c5 | ||
|
|
10c56e08d4 | ||
|
|
4af51b4a76 | ||
|
|
65cc03da14 | ||
|
|
e908cb0df5 | ||
|
|
ae2cee3fda | ||
|
|
0467ed7ffc | ||
|
|
d5453b4aa4 | ||
|
|
7096a785db | ||
|
|
c80db13c28 | ||
|
|
b971045cd2 | ||
|
|
61d4ccbf1b | ||
|
|
c3b237466c | ||
|
|
29c727319d | ||
|
|
52c5dc589d | ||
|
|
35cad9bf22 | ||
|
|
b108876017 | ||
|
|
52bfff953a | ||
|
|
65278c4489 | ||
|
|
3a4a925ab0 | ||
|
|
6ef5d41c25 | ||
|
|
b9b9f46fbe | ||
|
|
8d014e579d | ||
|
|
f2fc9f10f9 | ||
|
|
f131155fd8 | ||
|
|
691e24a1d8 | ||
|
|
794a6f4454 | ||
|
|
41bf8525cf | ||
|
|
6ebf486c09 | ||
|
|
899ae94fcf | ||
|
|
d3cd5019d9 | ||
|
|
1e4719558f | ||
|
|
29ab83b9c0 | ||
|
|
4b4d170ce1 | ||
|
|
8b0a12e0ba | ||
|
|
430318ead7 | ||
|
|
32f6ec63f2 | ||
|
|
a3181c8f76 | ||
|
|
412d169f58 | ||
|
|
d1c2e6e0dd | ||
|
|
4f9ac56de0 | ||
|
|
9641dc82f9 | ||
|
|
e68413b73c | ||
|
|
a7386a25bd | ||
|
|
53f512e864 | ||
|
|
283e643606 | ||
|
|
fc1aa2db83 | ||
|
|
0fc1e02519 | ||
|
|
67581bf3f6 | ||
|
|
b7e4ca4d87 | ||
|
|
0594fc60c0 | ||
|
|
5a6c51219c | ||
|
|
815542bf25 | ||
|
|
0c5bd817a9 | ||
|
|
9b8a317351 | ||
|
|
7a9d8e021a | ||
|
|
297ec1b8a1 | ||
|
|
f04f6684e0 | ||
|
|
91870c6712 | ||
|
|
9c48fcf5f8 | ||
|
|
ee41cfc618 | ||
|
|
ae30f89a2d | ||
|
|
dfcce3a974 | ||
|
|
59423df0cb | ||
|
|
ee08c486bc | ||
|
|
a56c522068 | ||
|
|
6d40eba496 | ||
|
|
c772df9d65 | ||
|
|
2a73f26f2a | ||
|
|
a750ade5a4 | ||
|
|
06b37c02f1 | ||
|
|
d129607d5c | ||
|
|
e6d812bbd8 | ||
|
|
9cc921098e | ||
|
|
38213c1a91 | ||
|
|
44d74924e6 | ||
|
|
5eaf0c12d3 | ||
|
|
7c2b433f7b | ||
|
|
30e692cefe | ||
|
|
396fb42b11 | ||
|
|
c8d882712e | ||
|
|
9667aad1cb | ||
|
|
4471303aae | ||
|
|
fe2ec8cc94 | ||
|
|
25440c6fec | ||
|
|
8c2d7243cc | ||
|
|
49e67a0bef | ||
|
|
1dfa937bff | ||
|
|
a3c6bbc1b5 | ||
|
|
241e8b6842 | ||
|
|
8660faaeb7 | ||
|
|
687deab6bc | ||
|
|
17ec3cbf4b | ||
|
|
f75609c98c | ||
|
|
5bd65cc06a | ||
|
|
e2177577be | ||
|
|
a695744c7c | ||
|
|
c2a89731c9 | ||
|
|
f0bfb08c2e | ||
|
|
764f7df6a7 | ||
|
|
c310822945 | ||
|
|
4cedd051b6 | ||
|
|
d36fe1ab12 | ||
|
|
9a14125c6b | ||
|
|
1a4ba51dec | ||
|
|
826fb3f110 | ||
|
|
9f42eb3ad7 | ||
|
|
fbbc333221 | ||
|
|
e62792b0da | ||
|
|
dbc435c4e1 | ||
|
|
ada2f2498e | ||
|
|
c736446872 | ||
|
|
a1e7d5b36f | ||
|
|
24fd5a5e0b | ||
|
|
bc4557432a | ||
|
|
5df4a76367 | ||
|
|
48d566fd98 | ||
|
|
f9cd328b3a | ||
|
|
a24c13d8ce | ||
|
|
8b5494d0a6 | ||
|
|
7f0e8f5591 | ||
|
|
14f4e09676 | ||
|
|
c5aa61e191 | ||
|
|
c50efd7efd | ||
|
|
c23c239ce9 | ||
|
|
5a1b92f060 | ||
|
|
b7375b5a8e | ||
|
|
c42b5b2bb6 | ||
|
|
809783cd53 | ||
|
|
b5c5a18216 | ||
|
|
49b4dca12c | ||
|
|
37b03e6e37 | ||
|
|
70b92b5961 | ||
|
|
f31da2a8e6 | ||
|
|
c68ff15f38 | ||
|
|
bd1fe2b1cd | ||
|
|
a1f3914054 | ||
|
|
2d9dc48076 | ||
|
|
c80c120153 | ||
|
|
b75c23772e | ||
|
|
d9a94bc59c | ||
|
|
e446ab4762 | ||
|
|
2a656d437e | ||
|
|
7473cd2264 | ||
|
|
9fb1c0fbbb | ||
|
|
4ae0e75dc9 | ||
|
|
2632ce537a | ||
|
|
4d79261851 | ||
|
|
fadae5e33e | ||
|
|
7f702b7025 | ||
|
|
db255a8b7e | ||
|
|
47b8d1de39 | ||
|
|
01ea1d2910 | ||
|
|
f5f8aa985e | ||
|
|
1a848cf5fe | ||
|
|
b748b05fbd | ||
|
|
9f2a9c32c0 | ||
|
|
92d0b0163a | ||
|
|
c50e2a4026 | ||
|
|
69ffa159c7 | ||
|
|
81089fc20a | ||
|
|
3d09f72c90 | ||
|
|
ef7d84b24d | ||
|
|
9b71f8ca4b | ||
|
|
04c3fc77cb | ||
|
|
c6cc6f4537 | ||
|
|
f31a4440f1 | ||
|
|
84b1e60803 | ||
|
|
a434a5f25d | ||
|
|
09e844a63f | ||
|
|
c55e114131 | ||
|
|
575fbc06aa | ||
|
|
19376805de | ||
|
|
5ea6a31bc2 | ||
|
|
2714ffe04d | ||
|
|
c38eac0e46 | ||
|
|
fccc57fd52 | ||
|
|
fea309da11 | ||
|
|
d867881162 | ||
|
|
af9a7d2fb3 | ||
|
|
259584b24f | ||
|
|
38f61f64c7 | ||
|
|
3e9bfba4d6 | ||
|
|
be26c7f080 | ||
|
|
6b8befdc67 | ||
|
|
423e4e429b | ||
|
|
53aba47915 | ||
|
|
87f90b004f | ||
|
|
0b96afb055 | ||
|
|
8e99ebe5ef | ||
|
|
6e06d954fe | ||
|
|
497abb83da | ||
|
|
7ffebd97b9 | ||
|
|
55a5855720 | ||
|
|
adc828dc8a | ||
|
|
6c5c9e0147 | ||
|
|
baa9ffb948 | ||
|
|
92541fec23 | ||
|
|
b1f6448ae0 | ||
|
|
fc72cf0451 | ||
|
|
c76d931b01 | ||
|
|
02ef37d381 | ||
|
|
329b420c0d | ||
|
|
10049d0c1f | ||
|
|
1e602d86bd | ||
|
|
f22ab0068e | ||
|
|
3700e45e7f | ||
|
|
36196a176e | ||
|
|
72907de5ef | ||
|
|
9a7385789e | ||
|
|
d13893d1c7 | ||
|
|
1a8031c75d | ||
|
|
9d10261a9f | ||
|
|
d0a7ff00fc | ||
|
|
b80d0ee458 | ||
|
|
53069492b1 | ||
|
|
3e2dad4a7e | ||
|
|
fca1e5355e | ||
|
|
47c0fd706f | ||
|
|
4c4ffb2f54 | ||
|
|
ade477c6e5 | ||
|
|
719b966709 | ||
|
|
2085c04717 | ||
|
|
12a4e34075 | ||
|
|
13dd81ebbd | ||
|
|
a9492eb25f | ||
|
|
4dabbb7590 | ||
|
|
64b78bddd6 | ||
|
|
5a02554380 | ||
|
|
c312f3917f | ||
|
|
30654af261 | ||
|
|
29aa329038 | ||
|
|
cfbb0d3bf6 | ||
|
|
388f77ea52 | ||
|
|
139c2f3c14 | ||
|
|
dab544bc93 | ||
|
|
0070fce88d | ||
|
|
c27ecfe339 | ||
|
|
746de90700 | ||
|
|
c580f1aff7 | ||
|
|
93b429af8b | ||
|
|
f0e2e783a8 | ||
|
|
9c2af4281a | ||
|
|
c12e25217b | ||
|
|
d5d0903591 | ||
|
|
72bde214a3 | ||
|
|
3ae2cbcd2c | ||
|
|
82b3f210f6 | ||
|
|
b8e67c558d | ||
|
|
371bcfbf5b | ||
|
|
d75f1ed966 | ||
|
|
5e4c3e0fa4 | ||
|
|
2c2642a92a | ||
|
|
afa0a206bc | ||
|
|
57a8661988 | ||
|
|
a57b58b675 | ||
|
|
8b051462a8 | ||
|
|
3bde8373a3 | ||
|
|
73df161cd0 | ||
|
|
9c83fd14bc | ||
|
|
ab020a0654 | ||
|
|
14e77f3f9b | ||
|
|
730d717936 | ||
|
|
91a7a83cd5 | ||
|
|
6fb586e30f | ||
|
|
05b069ab8e | ||
|
|
33a9eca696 | ||
|
|
2b969c987c | ||
|
|
f6c15490cc | ||
|
|
da5e95595d | ||
|
|
56343b9d19 | ||
|
|
d2a4f5cbe5 | ||
|
|
bf5f071e9d | ||
|
|
5d14aac430 | ||
|
|
f69f895418 | ||
|
|
e572c34743 | ||
|
|
822f3a760f | ||
|
|
274c236860 | ||
|
|
29d074732d | ||
|
|
097cec5283 | ||
|
|
f0ee73f03b | ||
|
|
691110af2c | ||
|
|
1c7d3cc66d | ||
|
|
58df97961b | ||
|
|
61cefb3308 | ||
|
|
694b0178e6 | ||
|
|
48ae414941 | ||
|
|
b143767f8d | ||
|
|
11de24ad4f | ||
|
|
a9c5f2e184 | ||
|
|
ed3ad27560 | ||
|
|
a6632b6e3e | ||
|
|
2d49e7b4ce | ||
|
|
c097ad828d | ||
|
|
7125ee469f | ||
|
|
f91646f956 | ||
|
|
5bd86b6fb7 | ||
|
|
e12ed3e6f1 | ||
|
|
33a5d34bbf | ||
|
|
94662f5831 | ||
|
|
a37ffe5b4d | ||
|
|
fa1b421dad | ||
|
|
93727c52ae | ||
|
|
0108730004 | ||
|
|
10b97e708a | ||
|
|
cfa23ca27e | ||
|
|
5290eaefc7 | ||
|
|
2626b715ab | ||
|
|
99bc350f5f | ||
|
|
ee38441779 | ||
|
|
f0d31e0dc2 | ||
|
|
4a08b47c07 | ||
|
|
2d588a6498 | ||
|
|
510ec977b8 | ||
|
|
420a3d385d | ||
|
|
30185d1dbe | ||
|
|
642f949ae9 | ||
|
|
872804e1f4 | ||
|
|
b5a1575d5a | ||
|
|
95197f94be | ||
|
|
fedab57f29 | ||
|
|
3054c568ac | ||
|
|
c0fcc34f52 | ||
|
|
521e2bd7aa | ||
|
|
db4db08550 | ||
|
|
977f0204a7 | ||
|
|
78d12ddb03 | ||
|
|
433dcab02b | ||
|
|
c57563d5ca | ||
|
|
fcc4a44695 | ||
|
|
7d9f9b4d1f | ||
|
|
f790a9601f | ||
|
|
13d44d1ed9 | ||
|
|
d57ecd4eaa | ||
|
|
f14e5ba400 | ||
|
|
5638f435ba | ||
|
|
6b7b8a8203 | ||
|
|
942f95364e | ||
|
|
e997fb6679 | ||
|
|
3b8a96de23 | ||
|
|
75d6d10649 | ||
|
|
26736657fd | ||
|
|
27b6194d53 | ||
|
|
5c158db350 | ||
|
|
f54c173479 | ||
|
|
d51b337045 | ||
|
|
3d693a7b8d | ||
|
|
99f34ab71d | ||
|
|
cd2f95ac90 | ||
|
|
bacea59c0c | ||
|
|
f7e84a8f11 | ||
|
|
1452ddd5e4 | ||
|
|
abdbdd63f4 | ||
|
|
a92d2b585e | ||
|
|
3dae1bd104 | ||
|
|
e07c0c0981 | ||
|
|
b7dcd051b1 | ||
|
|
25223c8b85 | ||
|
|
d7b1a73777 | ||
|
|
df19d4d323 | ||
|
|
10bc4ed611 | ||
|
|
b063055e78 | ||
|
|
4f1f422701 | ||
|
|
7e44a3759f | ||
|
|
0a5a4ec0da | ||
|
|
c9a5280c7a | ||
|
|
c953498a9d | ||
|
|
c0ec8fcea2 | ||
|
|
7562444763 | ||
|
|
747add419e | ||
|
|
f242053d6c | ||
|
|
235df91a37 | ||
|
|
97ffa0bac2 | ||
|
|
c6bc7d93f4 | ||
|
|
bcc7573756 | ||
|
|
1f554816b6 | ||
|
|
411463bc57 | ||
|
|
1c26685c8c | ||
|
|
1dd4afa5e2 | ||
|
|
f9d4477cb1 | ||
|
|
6cbee09950 | ||
|
|
bcf6a5bd09 | ||
|
|
a00092f5cc | ||
|
|
b36b345ef3 | ||
|
|
029d97e21c | ||
|
|
13331e0709 | ||
|
|
68ad931728 | ||
|
|
475aa60bcd | ||
|
|
2937d8a022 | ||
|
|
6627510a59 | ||
|
|
ac9448cacc | ||
|
|
2d7b6717a9 | ||
|
|
c4aad2a4bd | ||
|
|
4566f23984 | ||
|
|
b6621fc333 | ||
|
|
084b2b357f | ||
|
|
aa5c63f467 | ||
|
|
c365065cdb | ||
|
|
e4a42de095 | ||
|
|
245935b7ac | ||
|
|
2540a8174f | ||
|
|
38c0a75759 | ||
|
|
eac5f20937 | ||
|
|
a71a2a7a4b | ||
|
|
856fdd3493 | ||
|
|
cbd54bdfe8 | ||
|
|
f294f8c740 | ||
|
|
3079976165 | ||
|
|
020005e89b | ||
|
|
b73a6d2a7f | ||
|
|
af5acd16f7 | ||
|
|
9d98dbb2a6 | ||
|
|
01406ca2e7 | ||
|
|
ca7010abb9 | ||
|
|
48c57d3d47 | ||
|
|
51b421c2b5 | ||
|
|
e3fc2a159a | ||
|
|
a624669b4d | ||
|
|
6c9862c634 | ||
|
|
525c7ade7c | ||
|
|
73d3f7b5c2 | ||
|
|
db13ae5fc8 | ||
|
|
e37c517f79 | ||
|
|
4a9093e0e9 | ||
|
|
4420c36889 | ||
|
|
6098eb6eac | ||
|
|
50b7c8a00c | ||
|
|
48d18b3866 | ||
|
|
c0627f342c | ||
|
|
92efc9ed8a | ||
|
|
00a0d35020 | ||
|
|
1cac9ad559 | ||
|
|
0f2c485d05 | ||
|
|
c4635f99c7 | ||
|
|
b31803780a | ||
|
|
86fe3aae1a | ||
|
|
9d0dda7fac | ||
|
|
5bc93be26d | ||
|
|
140aded113 | ||
|
|
3faa0f4f42 | ||
|
|
59b293c398 | ||
|
|
18f42b60b6 | ||
|
|
aa6c254997 | ||
|
|
44f7295830 | ||
|
|
22a75a886d | ||
|
|
7e5a43e95c | ||
|
|
db5ff8c7e1 | ||
|
|
d9758a7358 | ||
|
|
8ce6c26f9c | ||
|
|
9040b56ada | ||
|
|
15ad60f8a9 | ||
|
|
3b178d2645 | ||
|
|
21b7acd60b | ||
|
|
18a96d3286 | ||
|
|
2fd72cbd82 | ||
|
|
329a67cb21 | ||
|
|
9155ade937 | ||
|
|
9bcbcaefdf | ||
|
|
63794869a4 | ||
|
|
3631138978 | ||
|
|
c2ba998e7b | ||
|
|
93c62c6827 | ||
|
|
593c6ec09c | ||
|
|
8bb6ba2285 | ||
|
|
39e2254cd5 | ||
|
|
51f361f8d9 | ||
|
|
0c26af66d7 | ||
|
|
1f412fc1c6 | ||
|
|
1150f1af71 | ||
|
|
d0510509a4 | ||
|
|
d84444ae73 | ||
|
|
8ef7dee0b5 | ||
|
|
d658f70d2b | ||
|
|
308c0ec621 | ||
|
|
2f45a87f12 | ||
|
|
75ddba076f | ||
|
|
a2aefe5242 | ||
|
|
3259f83b9d | ||
|
|
65cd41b3c1 | ||
|
|
8a7d3e8d2a | ||
|
|
ce29c1f5cb | ||
|
|
f738469444 | ||
|
|
4ec25f7a60 | ||
|
|
c6ccffd1df | ||
|
|
539be8fca9 | ||
|
|
f53bf6a4a4 | ||
|
|
e9b4340a25 | ||
|
|
a5b075426b | ||
|
|
b58d26354d | ||
|
|
75f5066941 | ||
|
|
d40cebd34d |
43
.git-blame-ignore-revs
Normal file
43
.git-blame-ignore-revs
Normal file
@@ -0,0 +1,43 @@
|
||||
# `git blame` master ignore list.
|
||||
#
|
||||
# This file contains a list of git hashes of revisions to be ignored
|
||||
# by `git blame`. These revisions are considered "unimportant" in
|
||||
# that they are unlikely to be what you are interested in when blaming.
|
||||
# They are typically expected to be formatting-only changes.
|
||||
#
|
||||
# It can be used for `git blame` using `--ignore-revs-file` or by
|
||||
# setting `blame.ignoreRevsFile` in the `git config`[1].
|
||||
#
|
||||
# Ignore these commits when reporting with blame. Calling
|
||||
#
|
||||
# git blame --ignore-revs-file .git-blame-ignore-revs
|
||||
#
|
||||
# will tell `git blame` to ignore changes made by these revisions when
|
||||
# assigning blame, as if the change never happened.
|
||||
#
|
||||
# You can enable this as a default for your local repository by
|
||||
# running
|
||||
#
|
||||
# git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
#
|
||||
# This will probably be automatically picked by your IDE
|
||||
# (VSCode+GitLens and JetBrains products are confirmed to do this).
|
||||
#
|
||||
# Important: if you are switching to a branch without this file,
|
||||
# `git blame` will fail with an error.
|
||||
#
|
||||
# GitHub also excludes the commits listed below from its "Blame"
|
||||
# views[2][3].
|
||||
#
|
||||
# [1]: https://git-scm.com/docs/git-blame#Documentation/git-blame.txt-blameignoreRevsFile
|
||||
# [2]: https://github.blog/changelog/2022-03-24-ignore-commits-in-the-blame-view-beta/
|
||||
# [3]: https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view
|
||||
|
||||
|
||||
# Black changes
|
||||
465a88154152fb0607a63fa24c8446bff43ec886
|
||||
f06891926661986fff52d6eb4b4cb120c71972d1
|
||||
9bcbcaefdfecc85aedfd8e2f8aaa1ca7f959404e
|
||||
433dcab02b29f7bd3827e237434034deecc1b549
|
||||
9f6a9f991222efccc87b45a701086c95629c67b6
|
||||
f89114ca7e1b20bf8e645ecd0b52b707ec857aa9
|
||||
31
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
31
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: Bug report
|
||||
description: >
|
||||
Did you discover a bug in SABnzbd? Report it here!
|
||||
If you are not 100% certain this is a bug please go to our forums, Reddit or Discord server first.
|
||||
labels:
|
||||
- Support
|
||||
body:
|
||||
- type: input
|
||||
attributes:
|
||||
label: SABnzbd version
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Operating system
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Using Docker image
|
||||
options:
|
||||
- linuxserver
|
||||
- hotio
|
||||
- binhex
|
||||
- Other
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: Include error logs directly or link to extended logs on https://pastebin.com/
|
||||
validations:
|
||||
required: true
|
||||
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Support forum
|
||||
url: https://forums.sabnzbd.org/
|
||||
about: Support questions can be asked on our forums, Reddit or Discord server.
|
||||
- name: Discord
|
||||
url: https://discord.sabnzbd.org
|
||||
about: Support questions can be asked on our forums, Reddit or Discord server.
|
||||
- name: Reddit - r/sabnzbd
|
||||
url: https://www.reddit.com/r/sabnzbd
|
||||
about: Support questions can be asked on our forums, Reddit or Discord server.
|
||||
10
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
10
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
name: Feature request
|
||||
description: What new feature would you like to have added to SABnzbd?
|
||||
labels:
|
||||
- Support
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
validations:
|
||||
required: true
|
||||
47
.github/renovate.json
vendored
Normal file
47
.github/renovate.json
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base",
|
||||
":disableDependencyDashboard"
|
||||
],
|
||||
"schedule": [
|
||||
"before 8am on Monday"
|
||||
],
|
||||
"baseBranches": ["develop", "feature/uvicorn"],
|
||||
"pip_requirements": {
|
||||
"fileMatch": [
|
||||
"requirements.txt",
|
||||
"tests/requirements.txt",
|
||||
"builder/requirements.txt",
|
||||
"builder/release-requirements.txt"
|
||||
]
|
||||
},
|
||||
"ignorePaths": [],
|
||||
"ignoreDeps": [
|
||||
"jaraco.text",
|
||||
"jaraco.context",
|
||||
"jaraco.collections",
|
||||
"sabctools",
|
||||
"paho-mqtt",
|
||||
"werkzeug",
|
||||
"tavern"
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchManagers": ["github-actions"],
|
||||
"matchPackageNames": ["windows", "macos"],
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"matchPackagePatterns": [
|
||||
"*"
|
||||
],
|
||||
"groupName": "all dependencies",
|
||||
"groupSlug": "all",
|
||||
"separateMajorMinor": false,
|
||||
"automerge": true
|
||||
}
|
||||
],
|
||||
"automergeStrategy": "squash",
|
||||
"platformAutomerge": true
|
||||
}
|
||||
256
.github/workflows/build_release.yml
vendored
Normal file
256
.github/workflows/build_release.yml
vendored
Normal file
@@ -0,0 +1,256 @@
|
||||
name: Build binaries and source distribution
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
# Setting PYTHONNODEBUGRANGES reduces binary size
|
||||
env:
|
||||
PYTHONNODEBUGRANGES: 1
|
||||
|
||||
jobs:
|
||||
build_windows:
|
||||
name: Build Windows binary (${{ matrix.architecture }})
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- architecture: x64
|
||||
runs-on: windows-2022
|
||||
- architecture: arm64
|
||||
runs-on: windows-11-arm
|
||||
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.14"
|
||||
architecture: ${{ matrix.architecture }}
|
||||
cache: pip
|
||||
cache-dependency-path: "**/requirements.txt"
|
||||
- name: Install Python dependencies
|
||||
# Without dependencies to make sure everything is covered in the requirements.txt
|
||||
run: |
|
||||
python --version
|
||||
python -m pip install --upgrade pip wheel
|
||||
pip install --upgrade -r requirements.txt --no-dependencies
|
||||
pip install --upgrade -r builder/requirements.txt --no-dependencies
|
||||
- name: Build Windows standalone binary
|
||||
id: windows_binary
|
||||
run: python builder/package.py binary
|
||||
- name: Upload Windows standalone binary (unsigned)
|
||||
uses: actions/upload-artifact@v6
|
||||
id: upload-unsigned-binary
|
||||
with:
|
||||
path: "*-win*-bin.zip"
|
||||
name: Windows standalone binary (${{ matrix.architecture }})
|
||||
- name: Sign Windows standalone binary
|
||||
uses: signpath/github-action-submit-signing-request@v2
|
||||
if: contains(github.ref, 'refs/tags/')
|
||||
with:
|
||||
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
|
||||
organization-id: ${{ secrets.SIGNPATH_ORG_ID }}
|
||||
project-slug: "sabnzbd"
|
||||
artifact-configuration-slug: "sabnzbd-binary"
|
||||
signing-policy-slug: "release-signing"
|
||||
github-artifact-id: ${{ steps.upload-unsigned-binary.outputs.artifact-id }}
|
||||
wait-for-completion: true
|
||||
output-artifact-directory: "signed"
|
||||
- name: Upload Windows standalone binary (signed)
|
||||
uses: actions/upload-artifact@v6
|
||||
if: contains(github.ref, 'refs/tags/')
|
||||
with:
|
||||
name: Windows standalone binary (${{ matrix.architecture }}, signed)
|
||||
path: "signed"
|
||||
- name: Build Windows installer
|
||||
if: matrix.architecture == 'x64'
|
||||
run: python builder/package.py installer
|
||||
- name: Upload Windows installer
|
||||
if: matrix.architecture == 'x64'
|
||||
uses: actions/upload-artifact@v6
|
||||
id: upload-unsigned-installer
|
||||
with:
|
||||
path: "*-win-setup.exe"
|
||||
name: Windows installer (${{ matrix.architecture }})
|
||||
- name: Sign Windows installer
|
||||
if: matrix.architecture == 'x64' && contains(github.ref, 'refs/tags/')
|
||||
uses: signpath/github-action-submit-signing-request@v2
|
||||
with:
|
||||
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
|
||||
organization-id: ${{ secrets.SIGNPATH_ORG_ID }}
|
||||
project-slug: "sabnzbd"
|
||||
artifact-configuration-slug: "sabnzbd-installer"
|
||||
signing-policy-slug: "release-signing"
|
||||
github-artifact-id: ${{ steps.upload-unsigned-installer.outputs.artifact-id }}
|
||||
wait-for-completion: true
|
||||
output-artifact-directory: "signed"
|
||||
- name: Upload Windows installer (signed)
|
||||
if: matrix.architecture == 'x64' && contains(github.ref, 'refs/tags/')
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: Windows installer (${{ matrix.architecture }}, signed)
|
||||
path: "signed/*-win-setup.exe"
|
||||
|
||||
build_macos:
|
||||
name: Build macOS binary
|
||||
runs-on: macos-14
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
# We need the official Python, because the GA ones only support newer macOS versions
|
||||
# The deployment target is picked up by the Python build tools automatically
|
||||
# If updated, make sure to also set LSMinimumSystemVersion in SABnzbd.spec
|
||||
PYTHON_VERSION: "3.14.2"
|
||||
MACOSX_DEPLOYMENT_TARGET: "10.15"
|
||||
# We need to force compile for universal2 support
|
||||
CFLAGS: -arch x86_64 -arch arm64
|
||||
ARCHFLAGS: -arch x86_64 -arch arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up Python
|
||||
# Only use this for the caching of pip packages!
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.14"
|
||||
cache: pip
|
||||
cache-dependency-path: "**/requirements.txt"
|
||||
- name: Cache Python download
|
||||
id: cache-python-download
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/python.pkg
|
||||
key: cache-macOS-Python-${{ env.PYTHON_VERSION }}
|
||||
- name: Get Python from python.org
|
||||
if: steps.cache-python-download.outputs.cache-hit != 'true'
|
||||
run: curl https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-macos11.pkg -o ~/python.pkg
|
||||
- name: Install Python
|
||||
run: sudo installer -pkg ~/python.pkg -target /
|
||||
- name: Install Python dependencies
|
||||
# We have to manually compile some modules as they don't automatically fetch universal2 binaries
|
||||
run: |
|
||||
python3 --version
|
||||
pip3 install --upgrade pip wheel
|
||||
pip3 install --upgrade -r requirements.txt --no-binary cffi,CT3,PyYAML,charset_normalizer --no-dependencies
|
||||
pip3 install --upgrade -r builder/requirements.txt --no-dependencies
|
||||
- name: Import macOS codesign certificates
|
||||
# Taken from https://github.com/Apple-Actions/import-codesign-certs/pull/27 (comments)
|
||||
env:
|
||||
CERTIFICATES_P12: ${{ secrets.CERTIFICATES_P12 }}
|
||||
CERTIFICATES_P12_PASSWORD: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
|
||||
MACOS_KEYCHAIN_TEMP_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_TEMP_PASSWORD }}
|
||||
if: env.CERTIFICATES_P12
|
||||
run: |
|
||||
echo $CERTIFICATES_P12 | base64 --decode > certificate.p12
|
||||
security create-keychain -p "$MACOS_KEYCHAIN_TEMP_PASSWORD" build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p "$MACOS_KEYCHAIN_TEMP_PASSWORD" build.keychain
|
||||
security set-keychain-settings -lut 21600 build.keychain
|
||||
security import certificate.p12 -k build.keychain -P "$CERTIFICATES_P12_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign -T /usr/bin/xcrun
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_KEYCHAIN_TEMP_PASSWORD" build.keychain
|
||||
- name: Build source distribution
|
||||
# Run this on macOS so the line endings are correct by default
|
||||
run: python builder/package.py source
|
||||
- name: Upload source distribution
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
path: "*-src.tar.gz"
|
||||
name: Source distribution
|
||||
- name: Build macOS binary
|
||||
env:
|
||||
SIGNING_AUTH: ${{ secrets.SIGNING_AUTH }}
|
||||
NOTARIZATION_USER: ${{ secrets.NOTARIZATION_USER }}
|
||||
NOTARIZATION_PASS: ${{ secrets.NOTARIZATION_PASS }}
|
||||
run: |
|
||||
python3 builder/package.py app
|
||||
python3 builder/make_dmg.py
|
||||
- name: Upload macOS binary
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
path: "*-macos.dmg"
|
||||
name: macOS binary
|
||||
|
||||
build-snap:
|
||||
name: Build Snap Packages (${{ matrix.linux_arch }})
|
||||
timeout-minutes: 30
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
linux_arch: x64
|
||||
- os: ubuntu-24.04-arm
|
||||
linux_arch: arm64
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Cache par2cmdline-turbo tarball
|
||||
uses: actions/cache@v5
|
||||
id: cache-par2cmdline
|
||||
# Clearing the cache in case of new version requires manual clearing in GitHub!
|
||||
with:
|
||||
path: snap/par2cmdline.tar.gz
|
||||
key: cache-par2cmdline
|
||||
- name: Download par2cmdline-turbo tarball
|
||||
if: steps.cache-par2cmdline.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
PAR2_TARBALL=$(curl -sL https://api.github.com/repos/animetosho/par2cmdline-turbo/releases/latest | jq -r '.tarball_url')
|
||||
curl -o snap/par2cmdline.tar.gz -L "$PAR2_TARBALL"
|
||||
- uses: snapcore/action-build@v1
|
||||
name: Build snap
|
||||
id: snapcraft
|
||||
- name: Test snap installation
|
||||
run: |
|
||||
sudo snap install --dangerous *.snap
|
||||
sudo snap connect sabnzbd:removable-media
|
||||
# Basic smoke test - check that the binary exists and can show help
|
||||
timeout 10s snap run sabnzbd --help || true
|
||||
sudo snap remove sabnzbd
|
||||
- name: Upload snap
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: Snap package (${{ matrix.linux_arch }})
|
||||
path: ${{ steps.snapcraft.outputs.snap }}
|
||||
- name: Publish snap
|
||||
uses: snapcore/action-publish@v1
|
||||
if: contains(github.ref, 'refs/tags/')
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_TOKEN }}
|
||||
with:
|
||||
store_login: ${{ secrets.SNAP_TOKEN }}
|
||||
snap: ${{ steps.snapcraft.outputs.snap }}
|
||||
release: stable
|
||||
|
||||
release:
|
||||
name: Prepare Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_windows, build_macos]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.14"
|
||||
cache: pip
|
||||
cache-dependency-path: "builder/release-requirements.txt"
|
||||
- name: Download Source distribution artifact
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: Source distribution
|
||||
- name: Download macOS artifact
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: macOS binary
|
||||
- name: Download Windows artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: ${{ (contains(github.ref, 'refs/tags/')) && '*signed*' || '*Windows*' }}
|
||||
merge-multiple: true
|
||||
- name: Prepare official release
|
||||
env:
|
||||
AUTOMATION_GITHUB_TOKEN: ${{ secrets.AUTOMATION_GITHUB_TOKEN }}
|
||||
REDDIT_TOKEN: ${{ secrets.REDDIT_TOKEN }}
|
||||
run: |
|
||||
pip3 install -r builder/release-requirements.txt
|
||||
python3 builder/release.py
|
||||
63
.github/workflows/integration_testing.yml
vendored
Normal file
63
.github/workflows/integration_testing.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
name: CI Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
black:
|
||||
name: Black Code Formatter
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Black Code Formatter
|
||||
uses: lgeiger/black-action@master
|
||||
with:
|
||||
args: >
|
||||
SABnzbd.py
|
||||
sabnzbd
|
||||
scripts
|
||||
tools
|
||||
builder
|
||||
builder/SABnzbd.spec
|
||||
tests
|
||||
--line-length=120
|
||||
--target-version=py39
|
||||
--check
|
||||
--diff
|
||||
|
||||
test:
|
||||
name: Test ${{ matrix.name }} - Python ${{ matrix.python-version }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13", "3.14" ]
|
||||
name: ["Linux"]
|
||||
os: [ubuntu-latest]
|
||||
include:
|
||||
- name: macOS
|
||||
os: macos-latest
|
||||
python-version: "3.14"
|
||||
- name: Windows
|
||||
os: windows-2022
|
||||
python-version: "3.14"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: pip
|
||||
cache-dependency-path: "**/requirements.txt"
|
||||
- name: Install system dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt-get install unrar 7zip par2
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python --version
|
||||
python -m pip install --upgrade pip wheel
|
||||
pip install --upgrade -r requirements.txt --no-dependencies
|
||||
pip install --upgrade -r tests/requirements.txt
|
||||
- name: Test SABnzbd
|
||||
run: pytest -s
|
||||
33
.github/workflows/stale.yml
vendored
Normal file
33
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: "Close and lock old issues"
|
||||
on:
|
||||
schedule:
|
||||
- cron: "30 1 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
name: "Close stale issues"
|
||||
if: github.repository_owner == 'sabnzbd'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v10
|
||||
with:
|
||||
days-before-stale: 21
|
||||
days-before-close: 7
|
||||
stale-issue-label: "Stale"
|
||||
stale-issue-message: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
exempt-issue-labels: "Feature request, Work in progress, Bug"
|
||||
|
||||
lock:
|
||||
name: "Lock old issues"
|
||||
if: github.repository_owner == 'sabnzbd'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v6
|
||||
with:
|
||||
log-output: true
|
||||
issue-inactive-days: 60
|
||||
pr-inactive-days: 60
|
||||
43
.github/workflows/translations.yml
vendored
Normal file
43
.github/workflows/translations.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Update translatable texts
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
translations:
|
||||
name: Update translatable texts
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TX_TOKEN: ${{ secrets.TX_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
token: ${{ secrets.AUTOMATION_GITHUB_TOKEN }}
|
||||
- name: Generate translatable texts
|
||||
run: |
|
||||
python3 tools/extract_pot.py
|
||||
- name: Push/pull Transifex translations
|
||||
if: env.TX_TOKEN
|
||||
# Add --translation to the push command in order to update Transifex using local translation edits
|
||||
# However, this prevents modifying existing translations in Transifex as they will be overwritten by the push!
|
||||
run: |
|
||||
curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash
|
||||
./tx push --source
|
||||
./tx pull --all --force
|
||||
- name: Compile translations to validate them
|
||||
run: |
|
||||
python3 tools/make_mo.py
|
||||
- name: Push translatable and translated texts back to repo
|
||||
uses: stefanzweifel/git-auto-commit-action@v7.1.0
|
||||
if: env.TX_TOKEN
|
||||
with:
|
||||
commit_message: |
|
||||
Update translatable texts
|
||||
[skip ci]
|
||||
commit_user_name: SABnzbd Automation
|
||||
commit_user_email: bugs@sabnzbd.org
|
||||
commit_author: SABnzbd Automation <bugs@sabnzbd.org>
|
||||
file_pattern: "po/*.pot po/*.po"
|
||||
push_options: --force
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -31,6 +31,9 @@ SABnzbd-*/
|
||||
*.wp[ru]
|
||||
.idea
|
||||
|
||||
# VScode
|
||||
.vscode/
|
||||
|
||||
# Testing folders
|
||||
.cache
|
||||
.xprocess
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
path_classifiers:
|
||||
oldinterfaces:
|
||||
- interfaces/smpl
|
||||
- interfaces/Plush
|
||||
library:
|
||||
- "*knockout*"
|
||||
- "**/*min*"
|
||||
85
.travis.yml
85
.travis.yml
@@ -1,85 +0,0 @@
|
||||
# Include the host/username/password for the test-servers
|
||||
# Overwrite them for macOS, but shared for Linux
|
||||
env:
|
||||
global:
|
||||
- secure: iMXx74c2eUhDPJrukvAFxCFNWYDk8JB2alQ89Hc3T1ckXfDS37vgUplTze1aGo+AefUkDSFmTreFk9hVJvd4SQTHz4wS+qp7HQJFWECjR16jZwobIbukNPNU1JamozZoOa2igoVIJ8/tVIdIpfcsGfzj9WogwUlpChWHIiI8SM/Fc0WK+M9rDPKBpgjEN2yom73jbC2ETxuQ/HMdMNnNS9S1vS7MY+2W69+xi5Kl9hP0HUBIG/JtVXu1a4SO5NgqL5aW4cgKtgg0IjpedBRMcC0rpyEz+lDtl2jXYR+mXQEO8uNZOwzV7SLrq/ROGwW+DMtfiiySKxmuYoL/JOm4kcLyEup51dgnTQc1RdEcaYfk0twDry67prnQ/sXAQphzjl0StrTpLfzWUsCvgXRp7+XWhX9ElHN4KelOcAc7YeTSXoPY6bENk8LSy1woJ2HbH5TkSvtVJ6xrmssV3bEMp7aGx7qv1D/uvyAEMulB79WwdLyoDxmG9eIgXfp3nICko4p9kisrzK0hVCGDRCHSYgTnDBGTMJU/SlRRNUepmXHXQUrqWyTWvy2HTMUTjuYBaaNcUqZvyHyyaDq0MNBotwDCmes5o8fZu456lB/B26LwUu7cOSbCw19ePlGBNnbjA9NmNoQGOo66era3NEVJLYv+H91PAPQyWpzOt0X53Gk=
|
||||
- secure: Cryq31K8wxt+q212/q7IHlLf4flH4riaiHssxR0/VfGACtMp3jOAVZ5RAOvX03LPYp+BuX2KAHFXDHeGHGzYmESkpzPCToZ3GpaOwP3ymc3RNeU6bd98yEQyQtM/wtY4uxPUWdwz5Uw5kkeynxw3y/QFsYceipB3u3oCvfB9n8SqWShjWpBFyFhSKS/SJjUqgNcAaA0pTP8l/crquZNhkug/J8Nlc/nC0H6ZSJKGu8UhkhZ0VSEY8dofZZkGG6YCIIEAqGasQqkra6x/D0uECfQnnDrTqekvklUG31/zy+awQXl+0NjLTIKyl2rHp5AUpSTlbPO2mDYdbWEWcRYmNsEEiGfvy3R9kGGbNijB5b57jvgsJapH8DkGRWseISdCBWqLH7C/OafNuMGzQ4s3UCN1aazqqN/IAJplVjSWiKA76Nbh385x88E8RaH7Gnvx1ZK88Lgf7Bz8Ar/O1dMviyP8WbM/vQQkVMdOk89y5O6G8ZwHFoj/v8w383irWMN2iU0Mf7GKW91ughpKrrKbXCmkT1bR9+tNYpKWU1O+1jgnGk65149GNC0K+9exWt0TK3pNSUa7b2nVzxeAqdCJjCoKBi2pLiRxYVI50V80M2p5Xw+5iiSiOhTLzFLT3YRi2VBjjBFa8BHJHBS9Pua4DaFc1w06XNej6K8rRV5We0s=
|
||||
- secure: O/8jVULQmqOLHkvIW21IsVuL7/B+3MhgRFaT4wltxk/x7TarEsQyahXdStsQ+I53mMRbSfsArdCHXwgIm13wROXfcEdt7iM0f2tGWUsm32q73RrjBsKzb8SRTKZNkL1dOjpgkdEHejZdVckKlg0GlpJTTowOdfi+SYinj4Hj52vrV9waHk296njKw98W5Y35lEtSH3DcAU2NHrDi7YqQvjiBzj9MviG1qpJZJ1RMxKrTXXCqjlYcxr8FwO2kGpMnkTFIDywi4OspLQ1InEGhM9MdrY9tqGVzW631nX1uRV8aNhl+bLhtRs0i3QtOisWMWO5z5SQN6pOqUWx3nnwLPJzuoL+wGMDC2tdVRmH1+cuYCwq97curNq4hv9FBs7P/RS4e22WAoW0jtLWnx/5voVes1EsQE5iW/iG0z4ih3MIk3dHN6h8HcNr83DRxOW8JKmA79IbtcVFReZJ2AXQhx6VmvdUaIi3IKpW79K89ZzEuoEEO5Eyti2LLz9rti0iVknHejGYKWDCABflGaKjnj62tpUsAB9EsPPuwBegoKRd2bVy3kJ+RWGcMc4QfzsEq39z2ftQ8XJ800ZuuQvl7nsk86Dso+Hgr/T+5xU2wU6vFbwoDCWsxdnK2LXNpf3ci5PBZFhG9zLMRk+yFyAfh8OdQr19lxclay0X6na1K8i0=
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
language: python
|
||||
python: "3.5"
|
||||
- os: linux
|
||||
language: python
|
||||
python: "3.6"
|
||||
- os: linux
|
||||
language: python
|
||||
python: "3.7"
|
||||
- os: linux
|
||||
language: python
|
||||
python: "3.8"
|
||||
- os: osx
|
||||
addons:
|
||||
chrome: stable
|
||||
env:
|
||||
- HOMEBREW_NO_AUTO_UPDATE=1
|
||||
- secure: iMXx74c2eUhDPJrukvAFxCFNWYDk8JB2alQ89Hc3T1ckXfDS37vgUplTze1aGo+AefUkDSFmTreFk9hVJvd4SQTHz4wS+qp7HQJFWECjR16jZwobIbukNPNU1JamozZoOa2igoVIJ8/tVIdIpfcsGfzj9WogwUlpChWHIiI8SM/Fc0WK+M9rDPKBpgjEN2yom73jbC2ETxuQ/HMdMNnNS9S1vS7MY+2W69+xi5Kl9hP0HUBIG/JtVXu1a4SO5NgqL5aW4cgKtgg0IjpedBRMcC0rpyEz+lDtl2jXYR+mXQEO8uNZOwzV7SLrq/ROGwW+DMtfiiySKxmuYoL/JOm4kcLyEup51dgnTQc1RdEcaYfk0twDry67prnQ/sXAQphzjl0StrTpLfzWUsCvgXRp7+XWhX9ElHN4KelOcAc7YeTSXoPY6bENk8LSy1woJ2HbH5TkSvtVJ6xrmssV3bEMp7aGx7qv1D/uvyAEMulB79WwdLyoDxmG9eIgXfp3nICko4p9kisrzK0hVCGDRCHSYgTnDBGTMJU/SlRRNUepmXHXQUrqWyTWvy2HTMUTjuYBaaNcUqZvyHyyaDq0MNBotwDCmes5o8fZu456lB/B26LwUu7cOSbCw19ePlGBNnbjA9NmNoQGOo66era3NEVJLYv+H91PAPQyWpzOt0X53Gk=
|
||||
- secure: Yc9lY76AEXwG1uf+pg1xyTDo3gg8zsIqJ6K/WwJr7zStLGU6J5Qf/iW7jFzGxTbq0Kc6/dgb4VInYwlcyhjsRE3DI5LDqKiP2dZATP07crwZnzwrhxDPdYA+s1sI9YDJN90aZZm48DbUPFR7DPZjkDqyRJMRCFstZ/fJ//kSDVJvMjEOPEixzT6k5sRW2j9sctzEzqCHhroKaz5/m1sSBWa+pJx7C4A76NQFrMZEmlnWf0qKoUERaGn4hv5I3/38KQa0wy1q43obMoltmaFrbyIV4tx9M60kSGfaQdVVgwYgxPsINZeESJk+N4JCQSUKr0biAcKamPfgIbfEN4FbCGiFzHf5w/eIyUG0yUg42NtzzMVVS4I0s/aaPGKrjDrJNZ9bj8/oQjWDHtlRx7nrREdPI2Ch/MF8e8t03tDm5unhLIa6Fk1Ic9UbgwjtUqDvAne5+kwhsh8WpyU+VnttP/LyKTi2eqtADF6kPuxKM9DbTFE/IvCE2DXDFc6OOzAWoqhnbBgPrX0L5OlQLWoL13oi+yJMnBsF4Rd3rhqpNJ2sJTukeHT9z5yhkBEXHe9PatT0hiXZ7AxHsgX292k9Ti4se3pPxETkbR3r8iOklItMu1PViQsvfRyOFu+XloqMaPO31z48LmcPOps+/DYkbRyaTqBMdmPPRJghZ9lzvno=
|
||||
- secure: RsFCZq/1Q6/++mgCZB6WsnIcbBsBwHFn6nfwC+vAomxbPtHevdiC930eIn8jKDza6Vmd4LoaMklvNOBEK1QpphbZXhKZIecakZOb+KyHVanSbQwErZCuVQdEo2p8cHJfuEh3guxmkE2OjAiBnSsgHlLmGiLAUF5GW5NPDLASPXIxXbBKOIKv7sTWj6tYYfVdUs1pQVz3Z+MkhRoS2uhVBOvQ14axtAtil1WmhgEJzuHAvjW29b1Q6l2goIuqoglqwKSna437CCt6mMFt6IVQqi36/lwXw0cYCLyJq3PURGDce6FdeQlwW0YfOXwT9k6BH+HcNuYmCSAbuL5hqC994avYbpemsBKKGfBK0Q8xZe0lQpS+R1C+iF3XXnPLU8B5TtALiBcFVRd3s291mxigxYqjkXbkgwVNAgkXKze+MhvrEQgoQwwhU3SbnmrZN8U6wW58MDYzjDxPaZdE5tUI+ROkfWeMRqtQrGNSJX6AwjkCrurW1/n0DXMlsUFnq4WGWF9nk8aHVzD8Y0cetQ+tLj3HxuxNqmAquewn+Z7pL41YTHlSTZ9+nHhI0GLQem6ANWL/4xJO8nBeOUETv1nULgbMyNOVaS9yBA7b2omE+Zuf8CMRCr9ID+Eeqtx1cUSMkWRymTdZvyPFPLjQ9KASTc7aCM7Cfc0aBceOoOOxMRw=
|
||||
|
||||
install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||
LATEST_CHROMEDRIVER=$(curl -s https://chromedriver.storage.googleapis.com/LATEST_RELEASE) &&
|
||||
wget --no-verbose -O /tmp/chromedriver.zip https://chromedriver.storage.googleapis.com/$LATEST_CHROMEDRIVER/chromedriver_mac64.zip &&
|
||||
sudo unzip /tmp/chromedriver.zip chromedriver -d /usr/local/bin/;
|
||||
else
|
||||
sudo add-apt-repository ppa:jcfp -y;
|
||||
sudo apt-get update -q;
|
||||
sudo apt-get install unrar p7zip-full par2 chromium-chromedriver -y;
|
||||
ln -s /usr/lib/chromium-browser/chromedriver ~/bin/chromedriver;
|
||||
fi;
|
||||
- python3 --version
|
||||
- python3 -m pip install --upgrade pip
|
||||
- python3 -m pip install --upgrade wheel
|
||||
- python3 -m pip install --upgrade -r requirements.txt
|
||||
- python3 -m pip install --upgrade -r tests/requirements.txt
|
||||
|
||||
script:
|
||||
- python3 -m pytest
|
||||
|
||||
# Force code-style for folders that we already did, only on 1 job
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == "3.7" ]]; then
|
||||
python3 -m black
|
||||
scripts
|
||||
tools
|
||||
tests
|
||||
sabnzbd/utils
|
||||
sabnzbd/__init__.py
|
||||
sabnzbd/cfg.py
|
||||
sabnzbd/config.py
|
||||
sabnzbd/emailer.py
|
||||
sabnzbd/constants.py
|
||||
sabnzbd/decorators.py
|
||||
sabnzbd/decoder.py
|
||||
sabnzbd/database.py
|
||||
sabnzbd/getipaddress.py
|
||||
sabnzbd/filesystem.py
|
||||
sabnzbd/dirscanner.py
|
||||
sabnzbd/postproc.py
|
||||
sabnzbd/misc.py
|
||||
sabnzbd/lang.py
|
||||
sabnzbd/nzbparser.py
|
||||
sabnzbd/notifier.py
|
||||
sabnzbd/rss.py
|
||||
sabnzbd/par2file.py
|
||||
sabnzbd/version.py
|
||||
-l120 --check;
|
||||
fi
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
on_cancel: never
|
||||
on_failure: change
|
||||
23
.tx/config
Normal file
23
.tx/config
Normal file
@@ -0,0 +1,23 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[o:sabnzbd:p:sabnzbd-translations:r:po-main-sabnzbd-pot--develop]
|
||||
file_filter = po/main/<lang>.po
|
||||
minimum_perc = 0
|
||||
source_file = po/main/SABnzbd.pot
|
||||
source_lang = en
|
||||
type = PO
|
||||
|
||||
[o:sabnzbd:p:sabnzbd-translations:r:po-email-sabemail-pot--develop]
|
||||
file_filter = po/email/<lang>.po
|
||||
minimum_perc = 0
|
||||
source_file = po/email/SABemail.pot
|
||||
source_lang = en
|
||||
type = PO
|
||||
|
||||
[o:sabnzbd:p:sabnzbd-translations:r:po-nsis-sabnsis-pot--develop]
|
||||
file_filter = po/nsis/<lang>.po
|
||||
minimum_perc = 0
|
||||
source_file = po/nsis/SABnsis.pot
|
||||
source_lang = en
|
||||
type = PO
|
||||
16
ABOUT.txt
16
ABOUT.txt
@@ -1,16 +0,0 @@
|
||||
*******************************************
|
||||
*** This is SABnzbd 3.0.0 ***
|
||||
*******************************************
|
||||
|
||||
SABnzbd is an open-source cross-platform binary newsreader.
|
||||
It simplifies the process of downloading from Usenet dramatically,
|
||||
thanks to its friendly web-based user interface and advanced
|
||||
built-in post-processing options that automatically verify, repair,
|
||||
extract and clean up posts downloaded from Usenet.
|
||||
SABnzbd also has a fully customizable user interface,
|
||||
and offers a complete API for third-party applications to hook into.
|
||||
|
||||
There is an extensive Wiki on the use of SABnzbd.
|
||||
https://sabnzbd.org/wiki/
|
||||
|
||||
Please also read the file "ISSUES.txt"
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
(c) Copyright 2007-2020 by "The SABnzbd-team" <team@sabnzbd.org>
|
||||
(c) Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
|
||||
|
||||
The SABnzbd-team is:
|
||||
The SABnzbd-Team is:
|
||||
|
||||
Active team:
|
||||
Safihre
|
||||
|
||||
24
INSTALL.txt
24
INSTALL.txt
@@ -1,10 +1,10 @@
|
||||
SABnzbd 3.0.0
|
||||
SABnzbd
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
0) LICENSE
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
(c) Copyright 2007-2020 by "The SABnzbd-team" <team@sabnzbd.org>
|
||||
(c) Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
@@ -41,7 +41,7 @@ Use the "Help" button in the web-interface to be directed to the Help Wiki.
|
||||
-------------------------------------------------------------------------------
|
||||
3) INSTALL pre-built macOS binaries
|
||||
-------------------------------------------------------------------------------
|
||||
Download the DMG file, mount and drag the SABnzbd icon to Programs.
|
||||
Download the DMG file, mount and drag the SABnzbd icon to Applications.
|
||||
Just like you do with so many apps.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -52,19 +52,25 @@ Specific guides to install from source are available for Windows and macOS:
|
||||
https://sabnzbd.org/wiki/installation/install-macos
|
||||
https://sabnzbd.org/wiki/installation/install-from-source-windows
|
||||
|
||||
Only Python 3.5 and above is supported. Replace python3 with python in the commands
|
||||
below if Python 3 is the only version of Python on your system.
|
||||
Only Python 3.9 and above is supported.
|
||||
|
||||
Install all required Python packages by running:
|
||||
python3 -m pip install -r requirements.txt
|
||||
On Linux systems you need to install:
|
||||
par2 unrar python3-setuptools python3-pip
|
||||
|
||||
On non-X86 platforms, for which PyPI does not provide all pre-compiled packages,
|
||||
you also need to install these development libraries (exact names might differ per platform):
|
||||
libffi-dev libssl-dev
|
||||
|
||||
Unpack the ZIP-file containing the SABnzbd sources to any folder of your liking.
|
||||
|
||||
If you want multiple languages, you need to compile the translations.
|
||||
Inside the SABnzbd source directory, install all required Python packages by running:
|
||||
python3 -m pip install -r requirements.txt
|
||||
|
||||
If you want non-English languages, you need to compile the translations.
|
||||
Start this from a shell terminal (or command prompt):
|
||||
python3 tools/make_mo.py
|
||||
|
||||
Start this from a shell terminal (or command prompt):
|
||||
To start SABnzbd, run this from a shell terminal (or command prompt):
|
||||
python3 -OO SABnzbd.py
|
||||
|
||||
Within a few seconds your web browser will start and show the user interface.
|
||||
|
||||
28
ISSUES.txt
28
ISSUES.txt
@@ -14,15 +14,15 @@
|
||||
For these the server blocking method is not very favourable.
|
||||
There is an INI-only option that will limit blocks to 1 minute.
|
||||
no_penalties = 1
|
||||
See: https://sabnzbd.org/wiki/configuration/3.0/special
|
||||
See: https://sabnzbd.org/wiki/configuration/3.4/special
|
||||
|
||||
- Some third-party utilties try to probe SABnzbd API in such a way that you will
|
||||
- Some third-party utilities try to probe SABnzbd API in such a way that you will
|
||||
often see warnings about unauthenticated access.
|
||||
If you are sure these probes are harmless, you can suppress the warnings by
|
||||
setting the option "api_warnings" to 0.
|
||||
See: https://sabnzbd.org/wiki/configuration/3.0/special
|
||||
See: https://sabnzbd.org/wiki/configuration/3.4/special
|
||||
|
||||
- On OSX you may encounter downloaded files with foreign characters.
|
||||
- On macOS you may encounter downloaded files with foreign characters.
|
||||
The par2 repair may fail when the files were created on a Windows system.
|
||||
The problem is caused by the PAR2 utility and we cannot fix this now.
|
||||
This does not apply to files inside RAR files.
|
||||
@@ -33,25 +33,14 @@
|
||||
We cannot solve this problem, because the Operating System (read Windows)
|
||||
prevents the removal.
|
||||
|
||||
- Memory usage can sometimes have high peaks. This makes using SABnzbd on very low
|
||||
memory systems (e.g. a NAS device or a router) a challenge.
|
||||
In particular on Synology (SynoCommunity) the device may report that SABnzbd is using
|
||||
a lot of memory even when idle. In this case the memory is usually not actually used by
|
||||
SABnzbd and will be available if required by other apps or the system. More information
|
||||
can be found in the discussion here: https://github.com/SynoCommunity/spksrc/issues/2856
|
||||
|
||||
- SABnzbd is not compatible with some software firewall versions.
|
||||
The Microsoft Windows Firewall works fine, but remember to tell this
|
||||
firewall that SABnzbd is allowed to talk to other computers.
|
||||
|
||||
- When SABnzbd cannot send notification emails, check your virus scanner,
|
||||
firewall or security suite. It may be blocking outgoing email.
|
||||
|
||||
- When you are using external drives or network shares on OSX or Linux
|
||||
- When you are using external drives or network shares on macOS or Linux
|
||||
make sure that the drives are mounted.
|
||||
The operating system will simply redirect your files to alternative locations.
|
||||
You may have trouble finding the files when mounting the drive later.
|
||||
On OSX, SABnzbd will not create new folders in /Volumes.
|
||||
On macOS, SABnzbd will not create new folders in /Volumes.
|
||||
The result will be a failed job that can be retried once the volume has been mounted.
|
||||
|
||||
- If you use a mounted drive as "temporary download folder", it must be present when SABnzbd
|
||||
@@ -59,8 +48,3 @@
|
||||
You can make SABnzbd wait for a mount of the "temporary download folder" by setting
|
||||
Config->Special->wait_for_dfolder to 1.
|
||||
SABnzbd will appear to hang until the drive is mounted.
|
||||
|
||||
- If you experience speed-drops to KB/s when using a VPN, try setting the number of connections
|
||||
to your servers to a total of 7. There is a CPU-usage reduction feature in SABnzbd that
|
||||
gets confused by the way some VPN's handle the state of a connection. Below 8 connections
|
||||
this feature is not active.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(c) Copyright 2007-2020 by "The SABnzbd-team" <team@sabnzbd.org>
|
||||
(c) Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
|
||||
10
PKG-INFO
10
PKG-INFO
@@ -1,10 +0,0 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: SABnzbd
|
||||
Version: 3.0.0Beta2
|
||||
Summary: SABnzbd-3.0.0Beta2
|
||||
Home-page: https://sabnzbd.org
|
||||
Author: The SABnzbd Team
|
||||
Author-email: team@sabnzbd.org
|
||||
License: GNU General Public License 2 (GPL2 or later)
|
||||
Description: Fully automated Usenet Binary Downloader
|
||||
Platform: posix
|
||||
20
README.md
20
README.md
@@ -1,11 +1,8 @@
|
||||
SABnzbd - The automated Usenet download tool
|
||||
============================================
|
||||
|
||||
[](https://isitmaintained.com/project/sabnzbd/sabnzbd "Average time to resolve an issue")
|
||||
[](https://travis-ci.org/sabnzbd/sabnzbd)
|
||||
[](https://ci.appveyor.com/project/Safihre/sabnzbd)
|
||||
[](https://snapcraft.io/sabnzbd)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](https://discord.sabnzbd.org)
|
||||
|
||||
SABnzbd is an Open Source Binary Newsreader written in Python.
|
||||
|
||||
@@ -19,8 +16,8 @@ If you want to know more you can head over to our website: https://sabnzbd.org.
|
||||
|
||||
SABnzbd has a few dependencies you'll need before you can get running. If you've previously run SABnzbd from one of the various Linux packages, then you likely already have all the needed dependencies. If not, here's what you're looking for:
|
||||
|
||||
- `python` (Python 3.5 and higher, often called `python3`)
|
||||
- Python modules listed in `requirements.txt`
|
||||
- `python` (Python 3.9 and above, often called `python3`)
|
||||
- Python modules listed in `requirements.txt`. Install with `python3 -m pip install -r requirements.txt -U`
|
||||
- `par2` (Multi-threaded par2 installation guide can be found [here](https://sabnzbd.org/wiki/installation/multicore-par2))
|
||||
- `unrar` (make sure you get the "official" non-free version of unrar)
|
||||
|
||||
@@ -69,3 +66,12 @@ Conditions:
|
||||
- Bugfixes created specifically for a release branch are done there (because they are specific, they're not cherry-picked to `develop`).
|
||||
- Bugfixes done on `develop` may be cherry-picked to a release branch.
|
||||
- We will not release a 1.0.2 if a 1.1.0 has already been released.
|
||||
|
||||
## Privacy Policy
|
||||
|
||||
This program will not transfer any information to other networked systems unless
|
||||
specifically requested by the user or the person installing or operating it.
|
||||
|
||||
## Code Signing Policy
|
||||
|
||||
For our Windows release, free code signing is provided by [SignPath.io](https://signpath.io), certificate by [SignPath Foundation](https://signpath.org).
|
||||
|
||||
93
README.mkd
93
README.mkd
@@ -1,67 +1,52 @@
|
||||
Release Notes - SABnzbd 3.0.0 Beta 2
|
||||
Release Notes - SABnzbd 4.6.0 Beta 2
|
||||
=========================================================
|
||||
|
||||
## About this new version
|
||||
We have been working for months to upgrade the SABnzbd code from Python 2 to Python 3.
|
||||
Although it might not sound like a big change, we had to rewrite almost every part of
|
||||
the code. This also means that we might have introduced new bugs. We therefore encourage
|
||||
you to let us know of any errors or strange behavior you might notice!
|
||||
This is the second beta release of version 4.6.
|
||||
|
||||
## Changes and bugfixes since 3.0.0 Beta 1
|
||||
- Articles failing with CRC errors are now retried on other servers.
|
||||
- Linux: special permission bits are removed from files after download.
|
||||
- Add hover color for queue and history in Glitter Night.
|
||||
- Improvements to built-in internet bandwidth test.
|
||||
- Adding new NZB's could fail.
|
||||
- Some API-calls could result in errors.
|
||||
## New features in 4.6.0
|
||||
|
||||
## Big changes in 3.0.0
|
||||
- Python 3.5 and above are the only supported versions of Python.
|
||||
- Cache handling is greatly improved, resulting in more stable speeds on some systems.
|
||||
- SFV files, even obfuscated, will be used for renaming when there are no par2 files.
|
||||
- Fully obfuscated RAR-sets with no verification files are detected and extracted.
|
||||
- Built-in internet bandwidth test.
|
||||
- Windows Service support was changed. The service will need to be reinstalled!
|
||||
Documentation: https://sabnzbd.org/wiki/advanced/sabnzbd-as-a-windows-service
|
||||
- The Windows installer is 64-bit only, for 32-bit use the standalone package.
|
||||
* Added support for NNTP Pipelining which eliminates idle waiting between
|
||||
requests, significantly improving speeds on high-latency connections.
|
||||
Read more here: https://sabnzbd.org/wiki/advanced/nntp-pipelining
|
||||
* Dynamically increase Assembler limits on faster connections.
|
||||
* Improved disk speed measurement in Status window.
|
||||
* Enable `verify_xff_header` by default.
|
||||
* Reduce delays between jobs during post-processing.
|
||||
* If a download only has `.nzb` files inside, the new downloads
|
||||
will include the name of the original download.
|
||||
* Dropped support for Python 3.8.
|
||||
* Windows: Added Windows ARM (portable) release.
|
||||
|
||||
## Other changes since 2.3.9
|
||||
- Files that are fully identical are now skipped automatically.
|
||||
- Linux tray icon support was improved.
|
||||
- macOS features such as the menu and notifications now use native code.
|
||||
- In Python 3 OpenSSL 1.1.1 is used for Windows and macOS, as a result
|
||||
newsservers manually set to "RC4-MD5" cipher can no longer connect.
|
||||
Documentation: https://sabnzbd.org/wiki/advanced/ssl-ciphers
|
||||
- TLS1.3 support for newsserver connections.
|
||||
- SABYenc, par2 and unrar are now required to start downloading.
|
||||
- Growl-support was removed.
|
||||
- API-calls "tapi" and "qstatus" were removed.
|
||||
- The "smpl" skin was removed.
|
||||
## Bug fixes since 4.5.0
|
||||
|
||||
* `Check before download` could get stuck or fail to reject.
|
||||
* No error was shown in case NZB upload failed.
|
||||
* Correct mobile layout if `Full Width` is enabled.
|
||||
* Aborted Direct Unpack could result in no files being unpacked.
|
||||
* Windows: Tray icon disappears after Explorer restart.
|
||||
* macOS: Slow to start on some network setups.
|
||||
|
||||
## Bugfixes since 2.3.9
|
||||
- Resolved potential security issue in FAT-filesystem check.
|
||||
- Sample removal did not work if only 1 sample file was present.
|
||||
- Crash on badly formatted RSS-feeds or readout during editing.
|
||||
- Aborting jobs that can't be completed would sometimes not trigger.
|
||||
- Windows systems could enter standby state during downloading.
|
||||
- Some errors thrown by unrar were not caught.
|
||||
- Files and sockets were not always closed correctly.
|
||||
- Unwanted extension check was overly aggressively deleting folders
|
||||
|
||||
## Upgrade notices
|
||||
- When upgrading from 2.x.x or older the queue will be converted. Job order,
|
||||
settings and data will be preserved, but if you decide to go back to 2.x.x
|
||||
your queue cannot be downgraded again. But you can restore the jobs by going
|
||||
to the Status page and running Queue Repair.
|
||||
|
||||
* You can directly upgrade from version 3.0.0 and newer.
|
||||
* Upgrading from older versions will require performing a `Queue repair`.
|
||||
* Downgrading from version 4.2.0 or newer to 3.7.2 or older will require
|
||||
performing a `Queue repair` due to changes in the internal data format.
|
||||
|
||||
## Known problems and solutions
|
||||
- Read the file "ISSUES.txt"
|
||||
|
||||
* Read `ISSUES.txt` or https://sabnzbd.org/wiki/introduction/known-issues
|
||||
|
||||
## Code Signing Policy
|
||||
|
||||
Windows code signing is provided by SignPath.io using a SignPath Foundation certificate.
|
||||
|
||||
## About
|
||||
SABnzbd is an open-source cross-platform binary newsreader.
|
||||
It simplifies the process of downloading from Usenet dramatically, thanks
|
||||
to its web-based user interface and advanced built-in post-processing options
|
||||
that automatically verify, repair, extract and clean up posts downloaded
|
||||
from Usenet.
|
||||
|
||||
(c) Copyright 2007-2020 by "The SABnzbd-team" \<team@sabnzbd.org\>
|
||||
SABnzbd is an open-source cross-platform binary newsreader.
|
||||
It simplifies the process of downloading from Usenet dramatically, thanks to its web-based
|
||||
user interface and advanced built-in post-processing options that automatically verify, repair,
|
||||
extract and clean up posts downloaded from Usenet.
|
||||
|
||||
(c) Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
|
||||
|
||||
1366
SABnzbd.py
1366
SABnzbd.py
File diff suppressed because it is too large
Load Diff
25
appveyor.yml
25
appveyor.yml
@@ -1,25 +0,0 @@
|
||||
environment:
|
||||
SAB_NEWSSERVER_HOST:
|
||||
secure: 6SvOPWr5ypJeoumXJAZh90DLpk4C/5UAvzwyX7OOUr4=
|
||||
SAB_NEWSSERVER_USER:
|
||||
secure: Ty3ZG8T5vnacqIFPj5j5hg==
|
||||
SAB_NEWSSERVER_PASSWORD:
|
||||
secure: bO3XHtWTleVF9AqRV/V/nA==
|
||||
|
||||
# We only use 64bit to test anyway
|
||||
matrix:
|
||||
- PYTHON: "C:\\Python35-x64"
|
||||
- PYTHON: "C:\\Python36-x64"
|
||||
- PYTHON: "C:\\Python37-x64"
|
||||
- PYTHON: "C:\\Python38-x64"
|
||||
|
||||
install:
|
||||
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
||||
- python --version
|
||||
- python -m pip install --upgrade pip
|
||||
- python -m pip install --upgrade wheel
|
||||
- python -m pip install --upgrade -r requirements.txt
|
||||
- python -m pip install --upgrade -r tests/requirements.txt
|
||||
|
||||
build_script:
|
||||
- python -m pytest
|
||||
179
builder/SABnzbd.spec
Normal file
179
builder/SABnzbd.spec
Normal file
@@ -0,0 +1,179 @@
|
||||
# -*- mode: python -*-
|
||||
import os
|
||||
import sys
|
||||
|
||||
from PyInstaller.building.api import EXE, COLLECT, PYZ
|
||||
from PyInstaller.building.build_main import Analysis
|
||||
from PyInstaller.building.osx import BUNDLE
|
||||
from PyInstaller.utils.hooks import collect_data_files, collect_submodules
|
||||
|
||||
from builder.constants import EXTRA_FILES, EXTRA_FOLDERS, RELEASE_VERSION, RELEASE_VERSION_TUPLE
|
||||
|
||||
# Add extra files in the PyInstaller-spec
|
||||
extra_pyinstaller_files = []
|
||||
|
||||
# Add hidden imports
|
||||
extra_hiddenimports = ["Cheetah.DummyTransaction", "cheroot.ssl.builtin", "certifi"]
|
||||
extra_hiddenimports.extend(collect_submodules("apprise"))
|
||||
extra_hiddenimports.extend(collect_submodules("babelfish.converters"))
|
||||
extra_hiddenimports.extend(collect_submodules("guessit.data"))
|
||||
|
||||
# Add platform specific stuff
|
||||
if sys.platform == "darwin":
|
||||
extra_hiddenimports.extend(["objc", "PyObjCTools"])
|
||||
# macOS folders
|
||||
EXTRA_FOLDERS += ["macos/par2/", "macos/unrar/", "macos/7zip/"]
|
||||
# Add NZB-icon file
|
||||
extra_pyinstaller_files.append(("builder/macos/image/nzbfile.icns", "."))
|
||||
# Version information is set differently on macOS
|
||||
version_info = None
|
||||
else:
|
||||
# Build would fail on non-Windows
|
||||
from PyInstaller.utils.win32.versioninfo import (
|
||||
VSVersionInfo,
|
||||
FixedFileInfo,
|
||||
StringFileInfo,
|
||||
StringTable,
|
||||
StringStruct,
|
||||
VarFileInfo,
|
||||
VarStruct,
|
||||
)
|
||||
|
||||
# Windows
|
||||
extra_hiddenimports.extend(["win32timezone", "winrt.windows.foundation.collections"])
|
||||
EXTRA_FOLDERS += ["win/par2/", "win/unrar/", "win/7zip/"]
|
||||
EXTRA_FILES += ["portable.cmd"]
|
||||
|
||||
# Detailed instructions are in the PyInstaller documentation
|
||||
# We don't include the alpha/beta/rc in the counters
|
||||
version_info = VSVersionInfo(
|
||||
ffi=FixedFileInfo(
|
||||
filevers=RELEASE_VERSION_TUPLE,
|
||||
prodvers=RELEASE_VERSION_TUPLE,
|
||||
mask=0x3F,
|
||||
flags=0x0,
|
||||
OS=0x40004,
|
||||
fileType=0x1,
|
||||
subtype=0x0,
|
||||
date=(0, 0),
|
||||
),
|
||||
kids=[
|
||||
StringFileInfo(
|
||||
[
|
||||
StringTable(
|
||||
"040904B0",
|
||||
[
|
||||
StringStruct("Comments", f"SABnzbd {RELEASE_VERSION}"),
|
||||
StringStruct("CompanyName", "The SABnzbd-Team"),
|
||||
StringStruct("FileDescription", f"SABnzbd {RELEASE_VERSION}"),
|
||||
StringStruct("FileVersion", RELEASE_VERSION),
|
||||
StringStruct("LegalCopyright", "The SABnzbd-Team"),
|
||||
StringStruct("ProductName", f"SABnzbd {RELEASE_VERSION}"),
|
||||
StringStruct("ProductVersion", RELEASE_VERSION),
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
VarFileInfo([VarStruct("Translation", [1033, 1200])]),
|
||||
],
|
||||
)
|
||||
|
||||
# Process the extra-files and folders
|
||||
for file_item in EXTRA_FILES:
|
||||
extra_pyinstaller_files.append((file_item, "."))
|
||||
for folder_item in EXTRA_FOLDERS:
|
||||
extra_pyinstaller_files.append((folder_item, folder_item))
|
||||
|
||||
# Add babelfish data files
|
||||
extra_pyinstaller_files.extend(collect_data_files("babelfish"))
|
||||
extra_pyinstaller_files.extend(collect_data_files("guessit"))
|
||||
extra_pyinstaller_files.extend(collect_data_files("apprise"))
|
||||
extra_pyinstaller_files.extend(collect_data_files("dateutil"))
|
||||
|
||||
pyi_analysis = Analysis(
|
||||
["SABnzbd.py"],
|
||||
datas=extra_pyinstaller_files,
|
||||
hiddenimports=extra_hiddenimports,
|
||||
excludes=["ujson", "FixTk", "tcl", "tk", "_tkinter", "tkinter", "Tkinter", "pydoc", "pydoc_data.topics"],
|
||||
module_collection_mode={"apprise.plugins": "py"},
|
||||
)
|
||||
|
||||
pyz = PYZ(pyi_analysis.pure, pyi_analysis.zipped_data)
|
||||
|
||||
codesign_identity = os.environ.get("SIGNING_AUTH")
|
||||
if not codesign_identity:
|
||||
# PyInstaller needs specifically None, not just an empty value
|
||||
codesign_identity = None
|
||||
|
||||
# macOS specific parameters are ignored on other platforms
|
||||
exe = EXE(
|
||||
pyz,
|
||||
pyi_analysis.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name="SABnzbd",
|
||||
console=False,
|
||||
append_pkg=False,
|
||||
icon="icons/sabnzbd.ico",
|
||||
contents_directory=".",
|
||||
version=version_info,
|
||||
target_arch="universal2",
|
||||
entitlements_file="builder/macos/entitlements.plist",
|
||||
codesign_identity=codesign_identity,
|
||||
)
|
||||
|
||||
coll = COLLECT(exe, pyi_analysis.binaries, pyi_analysis.zipfiles, pyi_analysis.datas, name="SABnzbd")
|
||||
|
||||
# We need to run again for the console-app
|
||||
if sys.platform == "win32":
|
||||
# Enable console=True for this one
|
||||
console_exe = EXE(
|
||||
pyz,
|
||||
pyi_analysis.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name="SABnzbd-console",
|
||||
append_pkg=False,
|
||||
icon="icons/sabnzbd.ico",
|
||||
contents_directory=".",
|
||||
version=version_info,
|
||||
)
|
||||
|
||||
console_coll = COLLECT(
|
||||
console_exe,
|
||||
pyi_analysis.binaries,
|
||||
pyi_analysis.zipfiles,
|
||||
pyi_analysis.datas,
|
||||
name="SABnzbd-console",
|
||||
)
|
||||
|
||||
# Build the APP on macOS
|
||||
if sys.platform == "darwin":
|
||||
info_plist = {
|
||||
"NSUIElement": 1,
|
||||
"NSPrincipalClass": "NSApplication",
|
||||
"CFBundleShortVersionString": RELEASE_VERSION,
|
||||
"NSHumanReadableCopyright": "The SABnzbd-Team",
|
||||
"CFBundleIdentifier": "org.sabnzbd.sabnzbd",
|
||||
"CFBundleDocumentTypes": [
|
||||
{
|
||||
"CFBundleTypeExtensions": ["nzb"],
|
||||
"CFBundleTypeIconFile": "nzbfile.icns",
|
||||
"CFBundleTypeMIMETypes": ["text/nzb"],
|
||||
"CFBundleTypeName": "NZB File",
|
||||
"CFBundleTypeRole": "Viewer",
|
||||
"LSTypeIsPackage": 0,
|
||||
"NSPersistentStoreTypeKey": "Binary",
|
||||
}
|
||||
],
|
||||
"LSMinimumSystemVersion": "10.13",
|
||||
"LSEnvironment": {"LANG": "en_US.UTF-8", "LC_ALL": "en_US.UTF-8"},
|
||||
}
|
||||
|
||||
app = BUNDLE(
|
||||
coll,
|
||||
name="SABnzbd.app",
|
||||
icon="builder/macos/image/sabnzbdplus.icns",
|
||||
bundle_identifier="org.sabnzbd.sabnzbd",
|
||||
info_plist=info_plist,
|
||||
)
|
||||
79
builder/constants.py
Normal file
79
builder/constants.py
Normal file
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/python3 -OO
|
||||
# Copyright 2008-2025 by The SABnzbd-Team (sabnzbd.org)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
|
||||
# Constants
|
||||
VERSION_FILE = "sabnzbd/version.py"
|
||||
APPDATA_FILE = "linux/org.sabnzbd.sabnzbd.appdata.xml"
|
||||
|
||||
# To draft a release or not to draft a release?
|
||||
ON_GITHUB_ACTIONS = os.environ.get("CI", False)
|
||||
RELEASE_THIS = "refs/tags/" in os.environ.get("GITHUB_REF", "")
|
||||
|
||||
# Import version.py without the sabnzbd overhead
|
||||
with open(VERSION_FILE) as version_file:
|
||||
exec(version_file.read())
|
||||
RELEASE_VERSION = __version__
|
||||
|
||||
# Pre-releases are longer than 6 characters (e.g. 3.1.0Beta1 vs 3.1.0, but also 3.0.11)
|
||||
PRERELEASE = len(RELEASE_VERSION) > 5
|
||||
|
||||
# Parse the version info for Windows file properties information
|
||||
version_regexed = re.search(r"(\d+)\.(\d+)\.(\d+)([a-zA-Z]*)(\d*)", RELEASE_VERSION)
|
||||
RELEASE_VERSION_TUPLE = (int(version_regexed.group(1)), int(version_regexed.group(2)), int(version_regexed.group(3)), 0)
|
||||
RELEASE_VERSION_BASE = f"{RELEASE_VERSION_TUPLE[0]}.{RELEASE_VERSION_TUPLE[1]}.{RELEASE_VERSION_TUPLE[2]}"
|
||||
|
||||
# Define release name
|
||||
RELEASE_NAME = "SABnzbd-%s" % RELEASE_VERSION
|
||||
RELEASE_TITLE = "SABnzbd %s" % RELEASE_VERSION
|
||||
RELEASE_SRC = RELEASE_NAME + "-src.tar.gz"
|
||||
RELEASE_WIN_BIN_X64 = RELEASE_NAME + "-win64-bin.zip"
|
||||
RELEASE_WIN_BIN_ARM64 = RELEASE_NAME + "-win-arm64-bin.zip"
|
||||
RELEASE_WIN_INSTALLER = RELEASE_NAME + "-win-setup.exe"
|
||||
RELEASE_MACOS = RELEASE_NAME + "-macos.dmg"
|
||||
RELEASE_README = "README.mkd"
|
||||
|
||||
# Detect architecture
|
||||
RELEASE_WIN_BIN = RELEASE_WIN_BIN_X64
|
||||
if platform.machine() == "ARM64":
|
||||
RELEASE_WIN_BIN = RELEASE_WIN_BIN_ARM64
|
||||
|
||||
# Used in package.py and SABnzbd.spec
|
||||
EXTRA_FILES = [
|
||||
RELEASE_README,
|
||||
"README.txt",
|
||||
"INSTALL.txt",
|
||||
"LICENSE.txt",
|
||||
"GPL2.txt",
|
||||
"GPL3.txt",
|
||||
"COPYRIGHT.txt",
|
||||
"ISSUES.txt",
|
||||
]
|
||||
EXTRA_FOLDERS = [
|
||||
"scripts/",
|
||||
"licenses/",
|
||||
"locale/",
|
||||
"email/",
|
||||
"interfaces/Glitter/",
|
||||
"interfaces/wizard/",
|
||||
"interfaces/Config/",
|
||||
"scripts/",
|
||||
"icons/",
|
||||
]
|
||||
8
builder/macos/entitlements.plist
Normal file
8
builder/macos/entitlements.plist
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
builder/macos/image/nzbfile.icns
Normal file
BIN
builder/macos/image/nzbfile.icns
Normal file
Binary file not shown.
BIN
builder/macos/image/sabnzbd_new_bg.png
Normal file
BIN
builder/macos/image/sabnzbd_new_bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
BIN
builder/macos/image/sabnzbd_new_bg.psd
Normal file
BIN
builder/macos/image/sabnzbd_new_bg.psd
Normal file
Binary file not shown.
BIN
builder/macos/image/sabnzbdplus.icns
Normal file
BIN
builder/macos/image/sabnzbdplus.icns
Normal file
Binary file not shown.
206
builder/make_dmg.py
Normal file
206
builder/make_dmg.py
Normal file
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/python3 -OO
|
||||
# Copyright 2008-2025 by The SABnzbd-Team (sabnzbd.org)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import os
|
||||
from constants import RELEASE_VERSION
|
||||
|
||||
|
||||
# We need to call dmgbuild from command-line, so here we can setup how
|
||||
if __name__ == "__main__":
|
||||
# Check for DMGBuild
|
||||
try:
|
||||
import dmgbuild
|
||||
except Exception:
|
||||
print("Requires dmgbuild-module, use pip install dmgbuild")
|
||||
exit()
|
||||
|
||||
# Make sure we are in the src folder
|
||||
if not os.path.exists("builder"):
|
||||
raise FileNotFoundError("Run from the main SABnzbd source folder: python builder/package.py")
|
||||
|
||||
# Check if signing is possible
|
||||
authority = os.environ.get("SIGNING_AUTH")
|
||||
|
||||
# Extract version info and set DMG path
|
||||
# Create sub-folder to upload later
|
||||
release = RELEASE_VERSION
|
||||
prod = "SABnzbd-" + release
|
||||
fileDmg = prod + "-macos.dmg"
|
||||
|
||||
# Path to app file
|
||||
apppath = "dist/SABnzbd.app"
|
||||
|
||||
# Copy Readme
|
||||
readmepath = os.path.join(apppath, "Contents/Resources/README.txt")
|
||||
|
||||
# Path to background and the icon
|
||||
backgroundpath = "builder/macos/image/sabnzbd_new_bg.png"
|
||||
iconpath = "builder/macos/image/sabnzbdplus.icns"
|
||||
|
||||
# Make DMG
|
||||
print("Building DMG")
|
||||
dmgbuild.build_dmg(
|
||||
filename=fileDmg,
|
||||
volume_name=prod,
|
||||
settings_file="builder/make_dmg.py",
|
||||
defines={"app": apppath, "readme": readmepath, "background": backgroundpath, "iconpath": iconpath},
|
||||
)
|
||||
|
||||
# Resign APP
|
||||
if authority:
|
||||
print("Siging DMG")
|
||||
os.system('codesign --deep -f -i "org.sabnzbd.SABnzbd" -s "%s" "%s"' % (authority, fileDmg))
|
||||
print("Signed!")
|
||||
else:
|
||||
print("Signing skipped, missing SIGNING_AUTH.")
|
||||
exit()
|
||||
|
||||
|
||||
### START OF DMGBUILD SETTINGS
|
||||
### COPIED AND MODIFIED FROM THE EXAMPLE ONLINE
|
||||
application = defines.get("app", "AppName.app")
|
||||
readme = defines.get("readme", "ReadMe.rtf")
|
||||
appname = os.path.basename(application)
|
||||
|
||||
# .. Basics ....................................................................
|
||||
|
||||
# Volume format (see hdiutil create -help)
|
||||
format = defines.get("format", "UDBZ")
|
||||
|
||||
# Volume size (must be large enough for your files)
|
||||
size = defines.get("size", "100M")
|
||||
|
||||
# Files to include
|
||||
files = [application, readme]
|
||||
|
||||
# Symlinks to create
|
||||
symlinks = {"Applications": "/Applications"}
|
||||
|
||||
# Volume icon
|
||||
#
|
||||
# You can either define icon, in which case that icon file will be copied to the
|
||||
# image, *or* you can define badge_icon, in which case the icon file you specify
|
||||
# will be used to badge the system's Removable Disk icon
|
||||
#
|
||||
badge_icon = defines.get("iconpath", "")
|
||||
|
||||
# Where to put the icons
|
||||
icon_locations = {readme: (70, 160), appname: (295, 220), "Applications": (510, 220)}
|
||||
|
||||
# .. Window configuration ......................................................
|
||||
|
||||
# Window position in ((x, y), (w, h)) format
|
||||
window_rect = ((100, 100), (660, 360))
|
||||
|
||||
# Background
|
||||
#
|
||||
# This is a STRING containing any of the following:
|
||||
#
|
||||
# #3344ff - web-style RGB color
|
||||
# #34f - web-style RGB color, short form (#34f == #3344ff)
|
||||
# rgb(1,0,0) - RGB color, each value is between 0 and 1
|
||||
# hsl(120,1,.5) - HSL (hue saturation lightness) color
|
||||
# hwb(300,0,0) - HWB (hue whiteness blackness) color
|
||||
# cmyk(0,1,0,0) - CMYK color
|
||||
# goldenrod - X11/SVG named color
|
||||
# builtin-arrow - A simple built-in background with a blue arrow
|
||||
# /foo/bar/baz.png - The path to an image file
|
||||
#
|
||||
# Other color components may be expressed either in the range 0 to 1, or
|
||||
# as percentages (e.g. 60% is equivalent to 0.6).
|
||||
background = defines.get("background", "builtin-arrow")
|
||||
|
||||
show_status_bar = False
|
||||
show_tab_view = False
|
||||
show_toolbar = False
|
||||
show_pathbar = False
|
||||
show_sidebar = False
|
||||
sidebar_width = 0
|
||||
|
||||
# Select the default view; must be one of
|
||||
#
|
||||
# 'icon-view'
|
||||
# 'list-view'
|
||||
# 'column-view'
|
||||
# 'coverflow'
|
||||
#
|
||||
default_view = "icon-view"
|
||||
|
||||
# General view configuration
|
||||
show_icon_preview = False
|
||||
|
||||
# Set these to True to force inclusion of icon/list view settings (otherwise
|
||||
# we only include settings for the default view)
|
||||
include_icon_view_settings = "auto"
|
||||
include_list_view_settings = "auto"
|
||||
|
||||
# .. Icon view configuration ...................................................
|
||||
|
||||
arrange_by = None
|
||||
grid_offset = (0, 0)
|
||||
grid_spacing = 50
|
||||
scroll_position = (0, 0)
|
||||
label_pos = "bottom" # or 'right'
|
||||
text_size = 16
|
||||
icon_size = 64
|
||||
|
||||
# .. List view configuration ...................................................
|
||||
|
||||
# Column names are as follows:
|
||||
#
|
||||
# name
|
||||
# date-modified
|
||||
# date-created
|
||||
# date-added
|
||||
# date-last-opened
|
||||
# size
|
||||
# kind
|
||||
# label
|
||||
# version
|
||||
# comments
|
||||
#
|
||||
list_icon_size = 16
|
||||
list_text_size = 12
|
||||
list_scroll_position = (0, 0)
|
||||
list_sort_by = "name"
|
||||
list_use_relative_dates = True
|
||||
list_calculate_all_sizes = (False,)
|
||||
list_columns = ("name", "date-modified", "size", "kind", "date-added")
|
||||
list_column_widths = {
|
||||
"name": 300,
|
||||
"date-modified": 181,
|
||||
"date-created": 181,
|
||||
"date-added": 181,
|
||||
"date-last-opened": 181,
|
||||
"size": 97,
|
||||
"kind": 115,
|
||||
"label": 100,
|
||||
"version": 75,
|
||||
"comments": 300,
|
||||
}
|
||||
list_column_sort_directions = {
|
||||
"name": "ascending",
|
||||
"date-modified": "descending",
|
||||
"date-created": "descending",
|
||||
"date-added": "descending",
|
||||
"date-last-opened": "descending",
|
||||
"size": "descending",
|
||||
"kind": "ascending",
|
||||
"label": "ascending",
|
||||
"version": "ascending",
|
||||
"comments": "ascending",
|
||||
}
|
||||
511
builder/package.py
Normal file
511
builder/package.py
Normal file
@@ -0,0 +1,511 @@
|
||||
#!/usr/bin/python3 -OO
|
||||
# Copyright 2008-2025 by The SABnzbd-Team (sabnzbd.org)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import glob
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
import tempfile
|
||||
import time
|
||||
import shutil
|
||||
import subprocess
|
||||
import tarfile
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
import configobj
|
||||
import packaging.version
|
||||
|
||||
from constants import (
|
||||
RELEASE_VERSION,
|
||||
RELEASE_VERSION_TUPLE,
|
||||
VERSION_FILE,
|
||||
RELEASE_README,
|
||||
RELEASE_NAME,
|
||||
RELEASE_WIN_BIN,
|
||||
RELEASE_WIN_INSTALLER,
|
||||
ON_GITHUB_ACTIONS,
|
||||
RELEASE_THIS,
|
||||
RELEASE_SRC,
|
||||
EXTRA_FILES,
|
||||
EXTRA_FOLDERS,
|
||||
)
|
||||
|
||||
|
||||
# Support functions
|
||||
def safe_remove(path):
|
||||
"""Remove file without errors if the file doesn't exist
|
||||
Can also handle folders
|
||||
"""
|
||||
if os.path.exists(path):
|
||||
if os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
else:
|
||||
os.remove(path)
|
||||
|
||||
|
||||
def delete_files_glob(glob_pattern: str, allow_no_matches: bool = False):
|
||||
"""Delete one file or set of files from wild-card spec.
|
||||
We expect to match at least 1 file, to force expected behavior"""
|
||||
if files_to_remove := glob.glob(glob_pattern):
|
||||
for path in files_to_remove:
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
else:
|
||||
if not allow_no_matches:
|
||||
raise FileNotFoundError(f"No files found that match '{glob_pattern}'")
|
||||
|
||||
|
||||
def run_external_command(command: list[str], print_output: bool = True, **kwargs):
|
||||
"""Wrapper to ease the use of calling external programs"""
|
||||
process = subprocess.Popen(command, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kwargs)
|
||||
output, _ = process.communicate()
|
||||
ret = process.wait()
|
||||
if (output and print_output) or ret != 0:
|
||||
print(output)
|
||||
if ret != 0:
|
||||
raise RuntimeError("Command returned non-zero exit code %s!" % ret)
|
||||
return output
|
||||
|
||||
|
||||
def run_git_command(parms):
|
||||
"""Run git command, raise error if it failed"""
|
||||
return run_external_command(["git"] + parms)
|
||||
|
||||
|
||||
def patch_version_file(release_name):
|
||||
"""Patch in the Git commit hash, but only when this is
|
||||
an unmodified checkout
|
||||
"""
|
||||
git_output = run_git_command(["log", "-1"])
|
||||
for line in git_output.split("\n"):
|
||||
if "commit " in line:
|
||||
commit = line.split(" ")[1].strip()
|
||||
break
|
||||
else:
|
||||
raise TypeError("Commit hash not found")
|
||||
|
||||
with open(VERSION_FILE, "r") as ver:
|
||||
version_file = ver.read()
|
||||
|
||||
version_file = re.sub(r'__baseline__\s*=\s*"[^"]*"', '__baseline__ = "%s"' % commit, version_file)
|
||||
version_file = re.sub(r'__version__\s*=\s*"[^"]*"', '__version__ = "%s"' % release_name, version_file)
|
||||
|
||||
with open(VERSION_FILE, "w") as ver:
|
||||
ver.write(version_file)
|
||||
|
||||
|
||||
def test_macos_min_version(binary_path: str):
|
||||
# Skip check if nothing was set
|
||||
if macos_min_version := os.environ.get("MACOSX_DEPLOYMENT_TARGET"):
|
||||
# Skip any arm64 specific files
|
||||
if "arm64" in binary_path:
|
||||
print(f"Skipping arm64 binary {binary_path}")
|
||||
return
|
||||
|
||||
# Check minimum macOS version is at least mac OS10.13
|
||||
# We only check the x86_64 since for arm64 it's always macOS 11+
|
||||
print(f"Checking if binary supports macOS {macos_min_version} and above: {binary_path}")
|
||||
otool_output = run_external_command(
|
||||
[
|
||||
"otool",
|
||||
"-arch",
|
||||
"x86_64",
|
||||
"-l",
|
||||
binary_path,
|
||||
],
|
||||
print_output=False,
|
||||
)
|
||||
|
||||
# Parse the output for LC_BUILD_VERSION minos
|
||||
# The output is very large, so that's why we enumerate over it
|
||||
req_version = packaging.version.parse(macos_min_version)
|
||||
bin_version = None
|
||||
lines = otool_output.split("\n")
|
||||
for line_nr, line in enumerate(lines):
|
||||
if "LC_VERSION_MIN_MACOSX" in line:
|
||||
# Display the version in the next lines
|
||||
bin_version = packaging.version.parse(lines[line_nr + 2].split()[1])
|
||||
elif "minos" in line:
|
||||
bin_version = packaging.version.parse(line.split()[1])
|
||||
|
||||
if bin_version and bin_version > req_version:
|
||||
raise ValueError(f"{binary_path} requires {bin_version}, we want {req_version}")
|
||||
else:
|
||||
# We got the information we need
|
||||
break
|
||||
else:
|
||||
print(lines)
|
||||
raise RuntimeError(f"Could not determine minimum macOS version for {binary_path}")
|
||||
else:
|
||||
print(f"Skipping macOS version check, MACOSX_DEPLOYMENT_TARGET not set")
|
||||
|
||||
|
||||
def test_sab_binary(binary_path: str):
|
||||
"""Wrapper to have a simple start-up test for the binary"""
|
||||
with tempfile.TemporaryDirectory() as config_dir:
|
||||
sabnzbd_process = subprocess.Popen(
|
||||
[binary_path, "--browser", "0", "--logging", "2", "--config", config_dir],
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
||||
# Wait for SAB to respond
|
||||
base_url = "http://127.0.0.1:8080/"
|
||||
for _ in range(30):
|
||||
try:
|
||||
urllib.request.urlopen(base_url, timeout=1).read()
|
||||
break
|
||||
except Exception:
|
||||
time.sleep(1)
|
||||
else:
|
||||
# Print console output and give some time to print
|
||||
print(sabnzbd_process.stdout.read())
|
||||
time.sleep(1)
|
||||
raise urllib.error.URLError("Could not connect to SABnzbd")
|
||||
|
||||
# Open a number of API calls and pages, to see if we are really up
|
||||
pages_to_test = [
|
||||
"",
|
||||
"wizard",
|
||||
"config",
|
||||
"config/server",
|
||||
"config/categories",
|
||||
"config/scheduling",
|
||||
"config/rss",
|
||||
"config/general",
|
||||
"config/folders",
|
||||
"config/switches",
|
||||
"config/sorting",
|
||||
"config/notify",
|
||||
"config/special",
|
||||
"api?mode=version",
|
||||
]
|
||||
for url in pages_to_test:
|
||||
print("Testing: %s%s" % (base_url, url))
|
||||
if b"500 Internal Server Error" in urllib.request.urlopen(base_url + url, timeout=1).read():
|
||||
raise RuntimeError("Crash in %s" % url)
|
||||
|
||||
# Parse API-key so we can do a graceful shutdown
|
||||
sab_config = configobj.ConfigObj(os.path.join(config_dir, "sabnzbd.ini"))
|
||||
urllib.request.urlopen(base_url + "shutdown/?apikey=" + sab_config["misc"]["api_key"], timeout=10)
|
||||
sabnzbd_process.wait()
|
||||
|
||||
# Print logs for verification
|
||||
with open(os.path.join(config_dir, "logs", "sabnzbd.log"), "r") as log_file:
|
||||
# Wait after printing so the output is nicely displayed in case of problems
|
||||
print(log_text := log_file.read())
|
||||
time.sleep(5)
|
||||
|
||||
# Make sure no extra errors/warnings were reported
|
||||
if "ERROR" in log_text or "WARNING" in log_text:
|
||||
raise RuntimeError("Warning or error reported during execution")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Was any option supplied?
|
||||
if len(sys.argv) < 2:
|
||||
raise TypeError("Please specify what to do")
|
||||
|
||||
# Make sure we are in the src folder
|
||||
if not os.path.exists("builder"):
|
||||
raise FileNotFoundError("Run from the main SABnzbd source folder: python builder/package.py")
|
||||
|
||||
# Check if we have the needed certificates
|
||||
try:
|
||||
import certifi
|
||||
except ImportError:
|
||||
raise FileNotFoundError("Need certifi module")
|
||||
|
||||
# Patch release file
|
||||
patch_version_file(RELEASE_VERSION)
|
||||
|
||||
# Rename release notes file
|
||||
safe_remove("README.txt")
|
||||
shutil.copyfile(RELEASE_README, "README.txt")
|
||||
|
||||
# Compile translations
|
||||
if not os.path.exists("locale"):
|
||||
run_external_command([sys.executable, "tools/make_mo.py"])
|
||||
|
||||
# Check again if translations exist, fail otherwise
|
||||
if not os.path.exists("locale"):
|
||||
raise FileNotFoundError("Failed to compile language files")
|
||||
|
||||
if "binary" in sys.argv:
|
||||
# Must be run on Windows
|
||||
if sys.platform != "win32":
|
||||
raise RuntimeError("Binary should be created on Windows")
|
||||
|
||||
# Make sure we remove any existing build-folders
|
||||
safe_remove("build")
|
||||
safe_remove("dist")
|
||||
|
||||
# Remove any leftovers
|
||||
safe_remove(RELEASE_NAME)
|
||||
safe_remove(RELEASE_WIN_BIN)
|
||||
|
||||
# Run PyInstaller and check output
|
||||
shutil.copyfile("builder/SABnzbd.spec", "SABnzbd.spec")
|
||||
run_external_command([sys.executable, "-O", "-m", "PyInstaller", "SABnzbd.spec"])
|
||||
|
||||
shutil.copytree("dist/SABnzbd-console", "dist/SABnzbd", dirs_exist_ok=True)
|
||||
safe_remove("dist/SABnzbd-console")
|
||||
|
||||
# Remove unwanted DLL's
|
||||
shutil.rmtree("dist/SABnzbd/Pythonwin")
|
||||
delete_files_glob("dist/SABnzbd/api-ms-win*.dll", allow_no_matches=True)
|
||||
delete_files_glob("dist/SABnzbd/ucrtbase.dll", allow_no_matches=True)
|
||||
|
||||
# Test the release
|
||||
test_sab_binary("dist/SABnzbd/SABnzbd.exe")
|
||||
|
||||
# Create the archive
|
||||
run_external_command(["win/7zip/7za.exe", "a", RELEASE_WIN_BIN, "SABnzbd"], cwd="dist")
|
||||
shutil.move(f"dist/{RELEASE_WIN_BIN}", RELEASE_WIN_BIN)
|
||||
|
||||
if "installer" in sys.argv:
|
||||
# Check if we have the dist folder
|
||||
if not os.path.exists("dist/SABnzbd/SABnzbd.exe"):
|
||||
raise FileNotFoundError("SABnzbd executable not found, run binary creation first")
|
||||
|
||||
# Check if we have a signed version
|
||||
if os.path.exists(f"signed/{RELEASE_WIN_BIN}"):
|
||||
print("Using signed version of SABnzbd binaries")
|
||||
safe_remove("dist/SABnzbd")
|
||||
run_external_command(["win/7zip/7za.exe", "x", "-odist", f"signed/{RELEASE_WIN_BIN}"])
|
||||
|
||||
# Make sure it exists
|
||||
if not os.path.exists("dist/SABnzbd/SABnzbd.exe"):
|
||||
raise FileNotFoundError("SABnzbd executable not found, signed zip extraction failed")
|
||||
elif RELEASE_THIS:
|
||||
raise FileNotFoundError("Signed SABnzbd executable not found, required for release!")
|
||||
else:
|
||||
print("Using unsigned version of SABnzbd binaries")
|
||||
|
||||
# Compile NSIS translations
|
||||
safe_remove("NSIS_Installer.nsi")
|
||||
safe_remove("NSIS_Installer.nsi.tmp")
|
||||
shutil.copyfile("builder/win/NSIS_Installer.nsi", "NSIS_Installer.nsi")
|
||||
run_external_command([sys.executable, "tools/make_mo.py", "nsis"])
|
||||
|
||||
# Run NSIS to build installer
|
||||
run_external_command(
|
||||
[
|
||||
"makensis.exe",
|
||||
"/V3",
|
||||
"/DSAB_VERSION=%s" % RELEASE_VERSION,
|
||||
"/DSAB_VERSIONKEY=%s" % ".".join(map(str, RELEASE_VERSION_TUPLE)),
|
||||
"/DSAB_FILE=%s" % RELEASE_WIN_INSTALLER,
|
||||
"NSIS_Installer.nsi.tmp",
|
||||
]
|
||||
)
|
||||
|
||||
if "app" in sys.argv:
|
||||
# Must be run on macOS
|
||||
if sys.platform != "darwin":
|
||||
raise RuntimeError("App should be created on macOS")
|
||||
|
||||
# Who will sign and notarize this?
|
||||
authority = os.environ.get("SIGNING_AUTH")
|
||||
notarization_user = os.environ.get("NOTARIZATION_USER")
|
||||
notarization_pass = os.environ.get("NOTARIZATION_PASS")
|
||||
|
||||
# We need to sign all the included binaries before packaging them
|
||||
# Otherwise the signature of the main application becomes invalid
|
||||
if authority:
|
||||
files_to_sign = [
|
||||
"macos/par2/par2",
|
||||
"macos/unrar/unrar",
|
||||
"macos/unrar/arm64/unrar",
|
||||
"macos/7zip/7zz",
|
||||
]
|
||||
for file_to_sign in files_to_sign:
|
||||
# Make sure it supports the macOS versions we want first
|
||||
test_macos_min_version(file_to_sign)
|
||||
|
||||
# Then sign in
|
||||
print("Signing %s with hardened runtime" % file_to_sign)
|
||||
run_external_command(
|
||||
[
|
||||
"codesign",
|
||||
"--deep",
|
||||
"--force",
|
||||
"--timestamp",
|
||||
"--options",
|
||||
"runtime",
|
||||
"--entitlements",
|
||||
"builder/macos/entitlements.plist",
|
||||
"-s",
|
||||
authority,
|
||||
file_to_sign,
|
||||
],
|
||||
print_output=False,
|
||||
)
|
||||
print("Signed %s!" % file_to_sign)
|
||||
|
||||
# Run PyInstaller and check output
|
||||
shutil.copyfile("builder/SABnzbd.spec", "SABnzbd.spec")
|
||||
run_external_command([sys.executable, "-O", "-m", "PyInstaller", "SABnzbd.spec"])
|
||||
|
||||
# Make sure we created a fully universal2 release when releasing or during CI
|
||||
if RELEASE_THIS or ON_GITHUB_ACTIONS:
|
||||
for bin_to_check in glob.glob("dist/SABnzbd.app/**/*.so", recursive=True):
|
||||
print("Checking if binary is universal2: %s" % bin_to_check)
|
||||
file_output = run_external_command(["file", bin_to_check], print_output=False)
|
||||
# Make sure we have both arm64 and x86
|
||||
if not ("x86_64" in file_output and "arm64" in file_output):
|
||||
raise RuntimeError("Non-universal2 binary found!")
|
||||
|
||||
# Make sure it supports the macOS versions we want
|
||||
test_macos_min_version(bin_to_check)
|
||||
|
||||
# Only continue if we can sign
|
||||
if authority:
|
||||
# We use PyInstaller to sign the main SABnzbd executable and the SABnzbd.app
|
||||
files_already_signed = [
|
||||
"dist/SABnzbd.app/Contents/MacOS/SABnzbd",
|
||||
"dist/SABnzbd.app",
|
||||
]
|
||||
for file_to_check in files_already_signed:
|
||||
print("Checking signature of %s" % file_to_check)
|
||||
sign_result = run_external_command(
|
||||
[
|
||||
"codesign",
|
||||
"-dv",
|
||||
"-r-",
|
||||
file_to_check,
|
||||
],
|
||||
print_output=False,
|
||||
) + run_external_command(
|
||||
[
|
||||
"codesign",
|
||||
"--verify",
|
||||
"--deep",
|
||||
file_to_check,
|
||||
],
|
||||
print_output=False,
|
||||
)
|
||||
if authority not in sign_result or "adhoc" in sign_result or "invalid" in sign_result:
|
||||
raise RuntimeError("Signature of %s seems invalid!" % file_to_check)
|
||||
|
||||
# Always notarize, as newer macOS versions don't allow any code without it
|
||||
if notarization_user and notarization_pass:
|
||||
# Prepare zip to upload to notarization service
|
||||
print("Creating zip to send to Apple notarization service")
|
||||
# We need to use ditto, otherwise the signature gets lost!
|
||||
notarization_zip = RELEASE_NAME + ".zip"
|
||||
run_external_command(
|
||||
["ditto", "-c", "-k", "--sequesterRsrc", "--keepParent", "dist/SABnzbd.app", notarization_zip]
|
||||
)
|
||||
|
||||
# Upload to Apple
|
||||
print("Sending zip to Apple notarization service")
|
||||
upload_result = run_external_command(
|
||||
[
|
||||
"xcrun",
|
||||
"notarytool",
|
||||
"submit",
|
||||
notarization_zip,
|
||||
"--apple-id",
|
||||
notarization_user,
|
||||
"--team-id",
|
||||
authority,
|
||||
"--password",
|
||||
notarization_pass,
|
||||
"--wait",
|
||||
],
|
||||
)
|
||||
|
||||
# Check if success
|
||||
if "status: accepted" not in upload_result.lower():
|
||||
raise RuntimeError("Failed to notarize..")
|
||||
|
||||
# Staple the notarization!
|
||||
print("Approved! Stapling the result to the app")
|
||||
run_external_command(["xcrun", "stapler", "staple", "dist/SABnzbd.app"])
|
||||
else:
|
||||
print("Notarization skipped, NOTARIZATION_USER or NOTARIZATION_PASS missing.")
|
||||
else:
|
||||
print("Signing skipped, missing SIGNING_AUTH.")
|
||||
|
||||
# Test the release, as the very last step to not mess with any release code
|
||||
test_sab_binary("dist/SABnzbd.app/Contents/MacOS/SABnzbd")
|
||||
|
||||
if "source" in sys.argv:
|
||||
# Prepare Source distribution package.
|
||||
# We assume the sources are freshly cloned from the repo
|
||||
# Make sure all source files are Unix format
|
||||
src_folder = "srcdist"
|
||||
safe_remove(src_folder)
|
||||
os.mkdir(src_folder)
|
||||
|
||||
# Remove any leftovers
|
||||
safe_remove(RELEASE_SRC)
|
||||
|
||||
# Add extra files and folders need for source dist
|
||||
EXTRA_FOLDERS.extend(["sabnzbd/", "po/", "linux/", "tools/", "tests/"])
|
||||
EXTRA_FILES.extend(["SABnzbd.py", "requirements.txt"])
|
||||
|
||||
# Copy all folders and files to the new folder
|
||||
for source_folder in EXTRA_FOLDERS:
|
||||
shutil.copytree(source_folder, os.path.join(src_folder, source_folder), dirs_exist_ok=True)
|
||||
|
||||
# Copy all files
|
||||
for source_file in EXTRA_FILES:
|
||||
shutil.copyfile(source_file, os.path.join(src_folder, source_file))
|
||||
|
||||
# Make sure all line-endings are correct
|
||||
for input_filename in glob.glob("%s/**/*.*" % src_folder, recursive=True):
|
||||
base, ext = os.path.splitext(input_filename)
|
||||
if ext.lower() not in (".py", ".txt", ".css", ".js", ".tmpl", ".sh", ".cmd"):
|
||||
continue
|
||||
print(input_filename)
|
||||
|
||||
with open(input_filename, "rb") as input_data:
|
||||
data = input_data.read()
|
||||
data = data.replace(b"\r", b"")
|
||||
with open(input_filename, "wb") as output_data:
|
||||
output_data.write(data)
|
||||
|
||||
# Create tar.gz file for source distro
|
||||
with tarfile.open(RELEASE_SRC, "w:gz") as tar_output:
|
||||
for root, dirs, files in os.walk(src_folder):
|
||||
for _file in files:
|
||||
input_path = os.path.join(root, _file)
|
||||
if sys.platform == "win32":
|
||||
tar_path = input_path.replace("srcdist\\", RELEASE_NAME + "/").replace("\\", "/")
|
||||
else:
|
||||
tar_path = input_path.replace("srcdist/", RELEASE_NAME + "/")
|
||||
tarinfo = tar_output.gettarinfo(input_path, tar_path)
|
||||
tarinfo.uid = 0
|
||||
tarinfo.gid = 0
|
||||
if _file in ("SABnzbd.py", "Sample-PostProc.sh", "make_mo.py", "msgfmt.py"):
|
||||
# Force Linux/macOS scripts as executable
|
||||
tarinfo.mode = 0o755
|
||||
else:
|
||||
tarinfo.mode = 0o644
|
||||
|
||||
with open(input_path, "rb") as f:
|
||||
tar_output.addfile(tarinfo, f)
|
||||
|
||||
# Remove source folder
|
||||
safe_remove(src_folder)
|
||||
|
||||
# Reset!
|
||||
run_git_command(["reset", "--hard"])
|
||||
run_git_command(["clean", "-f"])
|
||||
2
builder/release-requirements.txt
Normal file
2
builder/release-requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
PyGithub==2.8.1
|
||||
praw==7.8.1
|
||||
272
builder/release.py
Normal file
272
builder/release.py
Normal file
@@ -0,0 +1,272 @@
|
||||
#!/usr/bin/python3 -OO
|
||||
# Copyright 2008-2025 by The SABnzbd-Team (sabnzbd.org)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import github
|
||||
import praw
|
||||
|
||||
from constants import (
|
||||
RELEASE_VERSION,
|
||||
RELEASE_VERSION_BASE,
|
||||
PRERELEASE,
|
||||
RELEASE_SRC,
|
||||
RELEASE_WIN_BIN_X64,
|
||||
RELEASE_WIN_BIN_ARM64,
|
||||
RELEASE_WIN_INSTALLER,
|
||||
RELEASE_MACOS,
|
||||
RELEASE_README,
|
||||
RELEASE_THIS,
|
||||
RELEASE_TITLE,
|
||||
APPDATA_FILE,
|
||||
ON_GITHUB_ACTIONS,
|
||||
)
|
||||
|
||||
# Verify we have all assets
|
||||
files_to_check = (
|
||||
RELEASE_SRC,
|
||||
RELEASE_WIN_BIN_X64,
|
||||
RELEASE_WIN_BIN_ARM64,
|
||||
RELEASE_WIN_INSTALLER,
|
||||
RELEASE_MACOS,
|
||||
RELEASE_README,
|
||||
)
|
||||
for file_to_check in files_to_check:
|
||||
if not os.path.exists(file_to_check):
|
||||
raise RuntimeError("Not all release files are present!")
|
||||
print("All release files are present")
|
||||
|
||||
# Verify that appdata file is updated
|
||||
if not isinstance(ET.parse(APPDATA_FILE).find(f"./releases/release[@version='{RELEASE_VERSION_BASE}']"), ET.Element):
|
||||
release_missing = f"Could not find {RELEASE_VERSION_BASE} in {APPDATA_FILE}"
|
||||
if RELEASE_THIS:
|
||||
raise RuntimeError(release_missing)
|
||||
elif ON_GITHUB_ACTIONS:
|
||||
print(f"::warning file={APPDATA_FILE},title=Missing release::{release_missing}")
|
||||
else:
|
||||
print(release_missing)
|
||||
|
||||
# Calculate hashes for Synology release
|
||||
with open(RELEASE_SRC, "rb") as inp_file:
|
||||
source_data = inp_file.read()
|
||||
|
||||
print("---- Synology spksrc digest hashes ---- ")
|
||||
print(RELEASE_SRC, "SHA1", hashlib.sha1(source_data).hexdigest())
|
||||
print(RELEASE_SRC, "SHA256", hashlib.sha256(source_data).hexdigest())
|
||||
print(RELEASE_SRC, "MD5", hashlib.md5(source_data).hexdigest())
|
||||
print("----")
|
||||
|
||||
# Check if tagged as release and check for token
|
||||
gh_token = os.environ.get("AUTOMATION_GITHUB_TOKEN", "")
|
||||
if RELEASE_THIS and gh_token:
|
||||
gh_obj = github.Github(auth=github.Auth.Token(gh_token))
|
||||
gh_repo = gh_obj.get_repo("sabnzbd/sabnzbd")
|
||||
|
||||
# Read the release notes
|
||||
with open(RELEASE_README, "r") as readme_file:
|
||||
readme_data = readme_file.read()
|
||||
|
||||
# We have to manually check if we already created this release
|
||||
for release in gh_repo.get_releases():
|
||||
if release.tag_name == RELEASE_VERSION:
|
||||
gh_release = release
|
||||
print("Found existing release %s" % gh_release.name)
|
||||
break
|
||||
else:
|
||||
# Did not find it, so create the release, use the GitHub tag we got as input
|
||||
print("Creating GitHub release SABnzbd %s" % RELEASE_VERSION)
|
||||
gh_release = gh_repo.create_git_release(
|
||||
tag=RELEASE_VERSION,
|
||||
name=RELEASE_TITLE,
|
||||
message=readme_data,
|
||||
draft=True,
|
||||
prerelease=PRERELEASE,
|
||||
)
|
||||
|
||||
# Fetch existing assets, as overwriting is not allowed by GitHub
|
||||
gh_assets = gh_release.get_assets()
|
||||
|
||||
# Upload the assets
|
||||
for file_to_check in files_to_check:
|
||||
if os.path.exists(file_to_check):
|
||||
# Check if this file was previously uploaded
|
||||
if gh_assets.totalCount:
|
||||
for gh_asset in gh_assets:
|
||||
if gh_asset.name == file_to_check:
|
||||
print("Removing existing asset %s " % gh_asset.name)
|
||||
gh_asset.delete_asset()
|
||||
# Upload the new one
|
||||
print("Uploading %s to release %s" % (file_to_check, gh_release.name))
|
||||
gh_release.upload_asset(file_to_check)
|
||||
|
||||
# Check if we now have all files
|
||||
gh_new_assets = gh_release.get_assets()
|
||||
if gh_new_assets.totalCount:
|
||||
all_assets = [gh_asset.name for gh_asset in gh_new_assets]
|
||||
|
||||
# Check if we have all files, using set-comparison
|
||||
if set(files_to_check) == set(all_assets):
|
||||
print("All assets present, releasing %s" % RELEASE_VERSION)
|
||||
# Publish release
|
||||
gh_release.update_release(
|
||||
tag_name=RELEASE_VERSION,
|
||||
name=RELEASE_TITLE,
|
||||
message=readme_data,
|
||||
draft=False,
|
||||
prerelease=PRERELEASE,
|
||||
)
|
||||
|
||||
# Update the website
|
||||
gh_repo_web = gh_obj.get_repo("sabnzbd/sabnzbd.github.io")
|
||||
# Check if the branch already exists, only create one if it doesn't
|
||||
skip_website_update = False
|
||||
try:
|
||||
gh_repo_web.get_branch(RELEASE_VERSION)
|
||||
print("Branch %s on sabnzbd/sabnzbd.github.io already exists, skipping update" % RELEASE_VERSION)
|
||||
skip_website_update = True
|
||||
except github.GithubException:
|
||||
# Create a new branch to have the changes
|
||||
sb = gh_repo_web.get_branch("master")
|
||||
print("Creating branch %s on sabnzbd/sabnzbd.github.io" % RELEASE_VERSION)
|
||||
new_branch = gh_repo_web.create_git_ref(ref="refs/heads/" + RELEASE_VERSION, sha=sb.commit.sha)
|
||||
|
||||
# Update the files
|
||||
if not skip_website_update:
|
||||
# We need bytes version to interact with GitHub
|
||||
RELEASE_VERSION_BYTES = RELEASE_VERSION.encode()
|
||||
|
||||
# Get all the version files
|
||||
latest_txt = gh_repo_web.get_contents("latest.txt")
|
||||
latest_txt_items = latest_txt.decoded_content.split()
|
||||
new_latest_txt_items = latest_txt_items[:2]
|
||||
config_yml = gh_repo_web.get_contents("_config.yml")
|
||||
if PRERELEASE:
|
||||
# If it's a pre-release, we append to current version in latest.txt
|
||||
new_latest_txt_items.extend([RELEASE_VERSION_BYTES, latest_txt_items[1]])
|
||||
# And replace in _config.yml
|
||||
new_config_yml = re.sub(
|
||||
b"latest_testing: '[^']*'",
|
||||
b"latest_testing: '%s'" % RELEASE_VERSION_BYTES,
|
||||
config_yml.decoded_content,
|
||||
)
|
||||
else:
|
||||
# New stable release, replace the version
|
||||
new_latest_txt_items[0] = RELEASE_VERSION_BYTES
|
||||
# And replace in _config.yml
|
||||
new_config_yml = re.sub(
|
||||
b"latest_testing: '[^']*'",
|
||||
b"latest_testing: ''",
|
||||
config_yml.decoded_content,
|
||||
)
|
||||
new_config_yml = re.sub(
|
||||
b"latest_stable: '[^']*'",
|
||||
b"latest_stable: '%s'" % RELEASE_VERSION_BYTES,
|
||||
new_config_yml,
|
||||
)
|
||||
# Also update the wiki-settings, these only use x.x notation
|
||||
new_config_yml = re.sub(
|
||||
b"wiki_version: '[^']*'",
|
||||
b"wiki_version: '%s'" % RELEASE_VERSION_BYTES[:3],
|
||||
new_config_yml,
|
||||
)
|
||||
|
||||
# Update the files
|
||||
print("Updating latest.txt")
|
||||
gh_repo_web.update_file(
|
||||
"latest.txt",
|
||||
"Release %s: latest.txt" % RELEASE_VERSION,
|
||||
b"\n".join(new_latest_txt_items),
|
||||
latest_txt.sha,
|
||||
RELEASE_VERSION,
|
||||
)
|
||||
print("Updating _config.yml")
|
||||
gh_repo_web.update_file(
|
||||
"_config.yml",
|
||||
"Release %s: _config.yml" % RELEASE_VERSION,
|
||||
new_config_yml,
|
||||
config_yml.sha,
|
||||
RELEASE_VERSION,
|
||||
)
|
||||
|
||||
# Create pull-request
|
||||
print("Creating pull request in sabnzbd/sabnzbd.github.io for the update")
|
||||
update_pr = gh_repo_web.create_pull(
|
||||
title="Release %s" % RELEASE_VERSION,
|
||||
base="master",
|
||||
body="Automated update of release files",
|
||||
head=RELEASE_VERSION,
|
||||
)
|
||||
|
||||
# Merge pull-request
|
||||
print("Merging pull request in sabnzbd/sabnzbd.github.io for the update")
|
||||
update_pr.merge(merge_method="squash")
|
||||
|
||||
# Only with GitHub success we proceed to Reddit
|
||||
if reddit_token := os.environ.get("REDDIT_TOKEN", ""):
|
||||
# Token format (without whitespace):
|
||||
# {
|
||||
# "client_id":"XXX",
|
||||
# "client_secret":"XXX",
|
||||
# "user_agent":"SABnzbd release script",
|
||||
# "username":"Safihre",
|
||||
# "password":"XXX"
|
||||
# }
|
||||
credentials = json.loads(reddit_token)
|
||||
reddit = praw.Reddit(**credentials)
|
||||
|
||||
subreddit_sabnzbd = reddit.subreddit("sabnzbd")
|
||||
subreddit_usenet = reddit.subreddit("usenet")
|
||||
|
||||
# Read the release notes
|
||||
with open(RELEASE_README, "r") as readme_file:
|
||||
readme_lines = readme_file.readlines()
|
||||
|
||||
# Put the download link after the title
|
||||
readme_lines[2] = "## https://sabnzbd.org/downloads\n\n"
|
||||
|
||||
# Use the header in the readme as title
|
||||
title = readme_lines[0]
|
||||
release_notes_text = "".join(readme_lines[2:])
|
||||
print("Posting release notes to Reddit")
|
||||
|
||||
# Only stable releases to r/usenet
|
||||
if not PRERELEASE:
|
||||
# Get correct flair-id (required by r/usenet)
|
||||
for flair in subreddit_usenet.flair.link_templates.user_selectable():
|
||||
if flair["flair_text"] == "News":
|
||||
print("Posting to r/usenet")
|
||||
submission = subreddit_usenet.submit(
|
||||
title, selftext=release_notes_text, flair_id=flair["flair_template_id"]
|
||||
)
|
||||
break
|
||||
else:
|
||||
raise ValueError("Could not locate flair_text for posting to r/usenet")
|
||||
|
||||
# Post always to r/SABnzbd
|
||||
print("Posting to r/sabnzbd")
|
||||
subreddit_sabnzbd.submit(title, selftext=release_notes_text)
|
||||
|
||||
else:
|
||||
print("Missing REDDIT_TOKEN")
|
||||
|
||||
else:
|
||||
print("To push release to GitHub, first tag the commit.")
|
||||
print("Or missing the AUTOMATION_GITHUB_TOKEN, cannot push to GitHub without it.")
|
||||
19
builder/requirements.txt
Normal file
19
builder/requirements.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
# Basic build requirements
|
||||
# Note that not all sub-dependencies are listed, but only ones we know could cause trouble
|
||||
pyinstaller==6.17.0
|
||||
packaging==25.0
|
||||
pyinstaller-hooks-contrib==2025.10
|
||||
altgraph==0.17.5
|
||||
wrapt==2.0.1
|
||||
setuptools==80.9.0
|
||||
|
||||
# For the Windows build
|
||||
pefile==2024.8.26; sys_platform == 'win32'
|
||||
pywin32-ctypes==0.2.3; sys_platform == 'win32'
|
||||
|
||||
# For the macOS build
|
||||
dmgbuild==1.6.6; sys_platform == 'darwin'
|
||||
mac-alias==2.2.3; sys_platform == 'darwin'
|
||||
macholib==1.16.4; sys_platform == 'darwin'
|
||||
ds-store==1.3.2; sys_platform == 'darwin'
|
||||
PyNaCl==1.6.1; sys_platform == 'darwin'
|
||||
442
builder/win/NSIS_Installer.nsi
Normal file
442
builder/win/NSIS_Installer.nsi
Normal file
@@ -0,0 +1,442 @@
|
||||
; -*- coding: utf-8 -*-
|
||||
;
|
||||
; Copyright 2008-2015 The SABnzbd-Team (sabnzbd.org)
|
||||
;
|
||||
; This program is free software; you can redistribute it and/or
|
||||
; modify it under the terms of the GNU General Public License
|
||||
; as published by the Free Software Foundation; either version 2
|
||||
; of the License, or (at your option) any later version.
|
||||
;
|
||||
; This program is distributed in the hope that it will be useful,
|
||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
; GNU General Public License for more details.
|
||||
;
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with this program; if not, write to the Free Software
|
||||
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Unicode true
|
||||
|
||||
!addplugindir builder\win\nsis\Plugins
|
||||
!addincludedir builder\win\nsis\Include
|
||||
|
||||
!include "MUI2.nsh"
|
||||
!include "registerExtension.nsh"
|
||||
!include "FileFunc.nsh"
|
||||
!include "LogicLib.nsh"
|
||||
!include "WinVer.nsh"
|
||||
!include "nsProcess.nsh"
|
||||
!include "x64.nsh"
|
||||
!include "servicelib.nsh"
|
||||
!include "StdUtils.nsh"
|
||||
|
||||
;------------------------------------------------------------------
|
||||
;
|
||||
; Macro for removing existing and the current installation
|
||||
; It shared by the installer and the uninstaller.
|
||||
;
|
||||
!define RemovePrev "!insertmacro RemovePrev"
|
||||
!macro RemovePrev idir
|
||||
; Remove the whole dir
|
||||
; Users should not be putting stuff here!
|
||||
RMDir /r "${idir}"
|
||||
!macroend
|
||||
|
||||
!define RemovePrevShortcuts "!insertmacro RemovePrevShortcuts"
|
||||
!macro RemovePrevShortcuts
|
||||
; Remove shortcuts, starting with current user ones (from old installs)
|
||||
SetShellVarContext current
|
||||
!insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
|
||||
Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd.lnk"
|
||||
Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
|
||||
Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd - SafeMode.lnk"
|
||||
Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd - Documentation.url"
|
||||
RMDir "$SMPROGRAMS\$MUI_TEMP"
|
||||
Delete "$SMPROGRAMS\Startup\SABnzbd.lnk"
|
||||
Delete "$DESKTOP\SABnzbd.lnk"
|
||||
|
||||
SetShellVarContext all
|
||||
!insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
|
||||
Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd.lnk"
|
||||
Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
|
||||
Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd - SafeMode.lnk"
|
||||
Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd - Documentation.url"
|
||||
RMDir "$SMPROGRAMS\$MUI_TEMP"
|
||||
Delete "$SMPROGRAMS\Startup\SABnzbd.lnk"
|
||||
Delete "$DESKTOP\SABnzbd.lnk"
|
||||
!macroend
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Define names of the product
|
||||
Name "SABnzbd ${SAB_VERSION}"
|
||||
VIProductVersion "${SAB_VERSIONKEY}"
|
||||
VIFileVersion "${SAB_VERSIONKEY}"
|
||||
|
||||
VIAddVersionKey "Comments" "SABnzbd ${SAB_VERSION}"
|
||||
VIAddVersionKey "CompanyName" "The SABnzbd-Team"
|
||||
VIAddVersionKey "FileDescription" "SABnzbd ${SAB_VERSION}"
|
||||
VIAddVersionKey "FileVersion" "${SAB_VERSION}"
|
||||
VIAddVersionKey "LegalCopyright" "The SABnzbd-Team"
|
||||
VIAddVersionKey "ProductName" "SABnzbd ${SAB_VERSION}"
|
||||
VIAddVersionKey "ProductVersion" "${SAB_VERSION}"
|
||||
|
||||
OutFile "${SAB_FILE}"
|
||||
InstallDir "$PROGRAMFILES\SABnzbd"
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Some default compiler settings (uncomment and change at will):
|
||||
SetCompress auto ; (can be off or force)
|
||||
SetDatablockOptimize on ; (can be off)
|
||||
CRCCheck on ; (can be off)
|
||||
AutoCloseWindow false ; (can be true for the window go away automatically at end)
|
||||
ShowInstDetails hide ; (can be show to have them shown, or nevershow to disable)
|
||||
SetDateSave off ; (can be on to have files restored to their original date)
|
||||
WindowIcon on
|
||||
SpaceTexts none
|
||||
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Vista/Win7 redirects $SMPROGRAMS to all users without this
|
||||
RequestExecutionLevel admin
|
||||
FileErrorText "If you have no admin rights, try to install into a user directory."
|
||||
|
||||
;------------------------------------------------------------------
|
||||
;Variables
|
||||
Var MUI_TEMP
|
||||
Var STARTMENU_FOLDER
|
||||
Var PREV_INST_DIR
|
||||
|
||||
;------------------------------------------------------------------
|
||||
;Interface Settings
|
||||
|
||||
!define MUI_ABORTWARNING
|
||||
|
||||
;Show all languages, despite user's codepage
|
||||
!define MUI_LANGDLL_ALLLANGUAGES
|
||||
|
||||
!define MUI_ICON "dist\SABnzbd\icons\sabnzbd.ico"
|
||||
|
||||
|
||||
;--------------------------------
|
||||
;Pages
|
||||
|
||||
!insertmacro MUI_PAGE_LICENSE "dist\SABnzbd\LICENSE.txt"
|
||||
!define MUI_COMPONENTSPAGE_NODESC
|
||||
!insertmacro MUI_PAGE_COMPONENTS
|
||||
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
|
||||
;Start Menu Folder Page Configuration
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\SABnzbd"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
|
||||
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "SABnzbd"
|
||||
;Remember the installer language
|
||||
!define MUI_LANGDLL_REGISTRY_ROOT "HKCU"
|
||||
!define MUI_LANGDLL_REGISTRY_KEY "Software\SABnzbd"
|
||||
!define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language"
|
||||
|
||||
!insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
|
||||
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!define MUI_FINISHPAGE_RUN
|
||||
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
|
||||
!define MUI_FINISHPAGE_RUN_TEXT $(MsgRunSAB)
|
||||
!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\README.txt"
|
||||
!define MUI_FINISHPAGE_SHOWREADME_TEXT $(MsgShowRelNote)
|
||||
!define MUI_FINISHPAGE_LINK $(MsgSupportUs)
|
||||
!define MUI_FINISHPAGE_LINK_LOCATION "https://sabnzbd.org/donate"
|
||||
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!define MUI_UNPAGE_COMPONENTSPAGE_NODESC
|
||||
!insertmacro MUI_UNPAGE_COMPONENTS
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Run as user-level at end of install
|
||||
Function PageFinishRun
|
||||
; Check if SABnzbd service is installed
|
||||
!insertmacro SERVICE "installed" "SABnzbd" ""
|
||||
Pop $0 ;response
|
||||
${If} $0 == true
|
||||
; Service is installed, start the service
|
||||
!insertmacro SERVICE "start" "SABnzbd" ""
|
||||
${Else}
|
||||
; Service not installed, run executable as user
|
||||
${StdUtils.ExecShellAsUser} $0 "$INSTDIR\SABnzbd.exe" "" ""
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Set supported languages
|
||||
;
|
||||
; If you edit this list you also need to edit apireg.py in SABnzbd!
|
||||
;
|
||||
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
|
||||
!insertmacro MUI_LANGUAGE "French"
|
||||
!insertmacro MUI_LANGUAGE "German"
|
||||
!insertmacro MUI_LANGUAGE "Dutch"
|
||||
!insertmacro MUI_LANGUAGE "Finnish"
|
||||
!insertmacro MUI_LANGUAGE "Polish"
|
||||
!insertmacro MUI_LANGUAGE "Swedish"
|
||||
!insertmacro MUI_LANGUAGE "Danish"
|
||||
!insertmacro MUI_LANGUAGE "Italian"
|
||||
!insertmacro MUI_LANGUAGE "Norwegian"
|
||||
!insertmacro MUI_LANGUAGE "Romanian"
|
||||
!insertmacro MUI_LANGUAGE "Spanish"
|
||||
!insertmacro MUI_LANGUAGE "PortugueseBR"
|
||||
!insertmacro MUI_LANGUAGE "Serbian"
|
||||
!insertmacro MUI_LANGUAGE "Turkish"
|
||||
!insertmacro MUI_LANGUAGE "Hebrew"
|
||||
!insertmacro MUI_LANGUAGE "Russian"
|
||||
!insertmacro MUI_LANGUAGE "Czech"
|
||||
!insertmacro MUI_LANGUAGE "SimpChinese"
|
||||
|
||||
|
||||
;------------------------------------------------------------------
|
||||
;Reserve Files
|
||||
;If you are using solid compression, files that are required before
|
||||
;the actual installation should be stored first in the data block,
|
||||
;because this will make your installer start faster.
|
||||
|
||||
!insertmacro MUI_RESERVEFILE_LANGDLL
|
||||
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; SECTION main program
|
||||
;
|
||||
Section "SABnzbd" SecDummy
|
||||
|
||||
SetOutPath "$INSTDIR"
|
||||
SetShellVarContext all
|
||||
|
||||
DetailPrint $(MsgShutting)
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Shutdown any running service
|
||||
|
||||
!insertmacro SERVICE "stop" "SABnzbd" ""
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Terminate SABnzbd.exe
|
||||
loop:
|
||||
${nsProcess::FindProcess} "SABnzbd.exe" $R0
|
||||
StrCmp $R0 0 0 endcheck
|
||||
${nsProcess::CloseProcess} "SABnzbd.exe" $R0
|
||||
Sleep 500
|
||||
Goto loop
|
||||
endcheck:
|
||||
${nsProcess::Unload}
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Make sure old versions are gone (reg-key already read in onInt)
|
||||
StrCmp $PREV_INST_DIR "" noPrevInstallRemove
|
||||
${RemovePrev} "$PREV_INST_DIR"
|
||||
Goto continueSetupAfterRemove
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Add firewall rules for new installs
|
||||
noPrevInstallRemove:
|
||||
liteFirewallW::AddRule "$INSTDIR\SABnzbd.exe" "SABnzbd"
|
||||
liteFirewallW::AddRule "$INSTDIR\SABnzbd-console.exe" "SABnzbd-console"
|
||||
|
||||
continueSetupAfterRemove:
|
||||
|
||||
; add files / whatever that need to be installed here.
|
||||
File /r "dist\SABnzbd\*"
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Add to registry
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" "" "$INSTDIR"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" "Installer Language" "$(MsgLangCode)"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayName" "SABnzbd ${SAB_VERSION}"
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "UninstallString" '"$INSTDIR\uninstall.exe"'
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayVersion" '${SAB_VERSION}'
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "Publisher" 'The SABnzbd-Team'
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "HelpLink" 'https://forums.sabnzbd.org/'
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "URLInfoAbout" 'https://sabnzbd.org/wiki/'
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "URLUpdateInfo" 'https://sabnzbd.org/'
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "Comments" 'The automated Usenet download tool'
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayIcon" '$INSTDIR\icons\sabnzbd.ico'
|
||||
|
||||
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "EstimatedSize" 40674
|
||||
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "NoRepair" -1
|
||||
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "NoModify" -1
|
||||
|
||||
WriteRegStr HKEY_CURRENT_USER "Software\Classes\AppUserModelId\SABnzbd" "DisplayName" "SABnzbd"
|
||||
WriteRegStr HKEY_CURRENT_USER "Software\Classes\AppUserModelId\SABnzbd" "IconUri" '$INSTDIR\icons\sabnzbd16_32.ico'
|
||||
|
||||
; write out uninstaller
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
|
||||
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
|
||||
;Create shortcuts
|
||||
CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\SABnzbd.lnk" "$INSTDIR\SABnzbd.exe"
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\SABnzbd - SafeMode.lnk" "$INSTDIR\SABnzbd.exe" "--server 127.0.0.1:8080 -b1 --no-login"
|
||||
WriteINIStr "$SMPROGRAMS\$STARTMENU_FOLDER\SABnzbd - Documentation.url" "InternetShortcut" "URL" "https://sabnzbd.org/wiki/"
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
|
||||
!insertmacro MUI_STARTMENU_WRITE_END
|
||||
SectionEnd ; end of default section
|
||||
|
||||
Section $(MsgIcon) desktop
|
||||
CreateShortCut "$DESKTOP\SABnzbd.lnk" "$INSTDIR\SABnzbd.exe"
|
||||
SectionEnd ; end of desktop icon section
|
||||
|
||||
Section $(MsgAssoc) assoc
|
||||
${registerExtension} "$INSTDIR\icons\nzb.ico" "$INSTDIR\SABnzbd.exe" ".nzb" "NZB File"
|
||||
${RefreshShellIcons}
|
||||
SectionEnd ; end of file association section
|
||||
|
||||
Section /o $(MsgRunAtStart) startup
|
||||
CreateShortCut "$SMPROGRAMS\Startup\SABnzbd.lnk" "$INSTDIR\SABnzbd.exe" "-b0"
|
||||
SectionEnd ;
|
||||
|
||||
;------------------------------------------------------------------
|
||||
Function .onInit
|
||||
; We need to modify the dir here for X64
|
||||
${If} ${RunningX64}
|
||||
StrCpy $INSTDIR "$PROGRAMFILES64\SABnzbd"
|
||||
${Else}
|
||||
MessageBox MB_OK|MB_ICONSTOP $(MsgOnly64bit)
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
; Python 3.9 no longer supports Windows 7
|
||||
${If} ${AtMostWin8}
|
||||
MessageBox MB_OK|MB_ICONSTOP $(MsgNoWin7)
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Change settings based on if SAB was already installed
|
||||
ReadRegStr $PREV_INST_DIR HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd" ""
|
||||
StrCmp $PREV_INST_DIR "" noPrevInstall
|
||||
; We want to use the user's custom dir if he used one
|
||||
StrCmp $PREV_INST_DIR "$PROGRAMFILES\SABnzbd" noSpecialDir
|
||||
StrCmp $PREV_INST_DIR "$PROGRAMFILES64\SABnzbd" noSpecialDir
|
||||
; Set what the user had before
|
||||
StrCpy $INSTDIR "$PREV_INST_DIR"
|
||||
noSpecialDir:
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Check what the user has currently set for install options
|
||||
SetShellVarContext current
|
||||
IfFileExists "$SMPROGRAMS\Startup\SABnzbd.lnk" 0 endCheckStartupCurrent
|
||||
SectionSetFlags ${startup} 1
|
||||
endCheckStartupCurrent:
|
||||
SetShellVarContext all
|
||||
IfFileExists "$SMPROGRAMS\Startup\SABnzbd.lnk" 0 endCheckStartup
|
||||
SectionSetFlags ${startup} 1
|
||||
endCheckStartup:
|
||||
|
||||
SetShellVarContext current
|
||||
IfFileExists "$DESKTOP\SABnzbd.lnk" endCheckDesktop 0
|
||||
; If not present for current user, first check all user folder
|
||||
SetShellVarContext all
|
||||
IfFileExists "$DESKTOP\SABnzbd.lnk" endCheckDesktop 0
|
||||
SectionSetFlags ${desktop} 0 ; SAB is installed but desktop-icon not, so uncheck it
|
||||
endCheckDesktop:
|
||||
SetShellVarContext all
|
||||
|
||||
Push $1
|
||||
ReadRegStr $1 HKCR ".nzb" "" ; read current file association
|
||||
StrCmp "$1" "NZB File" noPrevInstall 0
|
||||
SectionSetFlags ${assoc} 0 ; Uncheck it when it wasn't checked before
|
||||
noPrevInstall:
|
||||
|
||||
;--------------------------------
|
||||
; Display language chooser
|
||||
!insertmacro MUI_LANGDLL_DISPLAY
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Tell users about the service change
|
||||
;
|
||||
!insertmacro SERVICE "installed" "SABHelper" ""
|
||||
Pop $0 ;response
|
||||
${If} $0 == true
|
||||
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION $(MsgServChange) IDOK removeservices IDCANCEL exitinstall
|
||||
exitinstall:
|
||||
Abort
|
||||
removeservices:
|
||||
!insertmacro SERVICE "delete" "SABHelper" ""
|
||||
!insertmacro SERVICE "delete" "SABnzbd" ""
|
||||
${EndIf}
|
||||
|
||||
FunctionEnd
|
||||
|
||||
;--------------------------------
|
||||
; begin uninstall settings/section
|
||||
UninstallText $(MsgUninstall)
|
||||
|
||||
Section "un.$(MsgDelProgram)" Uninstall
|
||||
;make sure sabnzbd.exe isn't running..if so shut it down
|
||||
DetailPrint $(MsgShutting)
|
||||
${nsProcess::KillProcess} "SABnzbd.exe" $R0
|
||||
${nsProcess::Unload}
|
||||
|
||||
; add delete commands to delete whatever files/registry keys/etc you installed here.
|
||||
Delete "$INSTDIR\uninstall.exe"
|
||||
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd"
|
||||
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd"
|
||||
DeleteRegKey HKEY_CURRENT_USER "Software\Classes\AppUserModelId\SABnzbd"
|
||||
DeleteRegKey HKEY_CURRENT_USER "Software\SABnzbd"
|
||||
|
||||
${RemovePrev} "$INSTDIR"
|
||||
${RemovePrevShortcuts}
|
||||
|
||||
; Remove firewall entries
|
||||
liteFirewallW::RemoveRule "$INSTDIR\SABnzbd.exe" "SABnzbd"
|
||||
liteFirewallW::RemoveRule "$INSTDIR\SABnzbd-console.exe" "SABnzbd-console"
|
||||
|
||||
${unregisterExtension} ".nzb" "NZB File"
|
||||
${RefreshShellIcons}
|
||||
|
||||
SectionEnd ; end of uninstall section
|
||||
|
||||
Section /o "un.$(MsgDelSettings)" DelSettings
|
||||
DetailPrint "Uninstall settings $LOCALAPPDATA"
|
||||
Delete "$LOCALAPPDATA\sabnzbd\sabnzbd.ini"
|
||||
RMDir /r "$LOCALAPPDATA\sabnzbd"
|
||||
SectionEnd
|
||||
|
||||
; eof
|
||||
|
||||
;--------------------------------
|
||||
;Language strings
|
||||
LangString MsgShowRelNote ${LANG_ENGLISH} "Show Release Notes"
|
||||
|
||||
LangString MsgRunSAB ${LANG_ENGLISH} "Run SABnzbd"
|
||||
|
||||
LangString MsgSupportUs ${LANG_ENGLISH} "Support the project, Donate!"
|
||||
|
||||
LangString MsgServChange ${LANG_ENGLISH} "The SABnzbd Windows Service changed in SABnzbd 3.0.0. $\nYou will need to reinstall the SABnzbd service. $\n$\nClick `OK` to remove the existing services or `Cancel` to cancel this upgrade."
|
||||
|
||||
LangString MsgOnly64bit ${LANG_ENGLISH} "SABnzbd only supports 64-bit Windows."
|
||||
|
||||
LangString MsgNoWin7 ${LANG_ENGLISH} "SABnzbd only supports Windows 8.1 and above."
|
||||
|
||||
LangString MsgShutting ${LANG_ENGLISH} "Shutting down SABnzbd"
|
||||
|
||||
LangString MsgUninstall ${LANG_ENGLISH} "This will uninstall SABnzbd from your system"
|
||||
|
||||
LangString MsgRunAtStart ${LANG_ENGLISH} "Run at startup"
|
||||
|
||||
LangString MsgIcon ${LANG_ENGLISH} "Desktop Icon"
|
||||
|
||||
LangString MsgAssoc ${LANG_ENGLISH} "NZB File association"
|
||||
|
||||
LangString MsgDelProgram ${LANG_ENGLISH} "Delete Program"
|
||||
|
||||
LangString MsgDelSettings ${LANG_ENGLISH} "Delete Settings"
|
||||
|
||||
LangString MsgLangCode ${LANG_ENGLISH} "en"
|
||||
|
||||
Function un.onInit
|
||||
!insertmacro MUI_UNGETLANGUAGE
|
||||
FunctionEnd
|
||||
501
builder/win/nsis/Include/StdUtils.nsh
Normal file
501
builder/win/nsis/Include/StdUtils.nsh
Normal file
@@ -0,0 +1,501 @@
|
||||
#################################################################################
|
||||
# StdUtils plug-in for NSIS
|
||||
# Copyright (C) 2004-2018 LoRd_MuldeR <MuldeR2@GMX.de>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# http://www.gnu.org/licenses/lgpl-2.1.txt
|
||||
#################################################################################
|
||||
|
||||
# DEVELOPER NOTES:
|
||||
# - Please see "https://github.com/lordmulder/stdutils/" for news and updates!
|
||||
# - Please see "Docs\StdUtils\StdUtils.html" for detailed function descriptions!
|
||||
# - Please see "Examples\StdUtils\StdUtilsTest.nsi" for usage examples!
|
||||
|
||||
#################################################################################
|
||||
# FUNCTION DECLARTIONS
|
||||
#################################################################################
|
||||
|
||||
!ifndef ___STDUTILS__NSH___
|
||||
!define ___STDUTILS__NSH___
|
||||
|
||||
!define StdUtils.Time '!insertmacro _StdU_Time' #time(), as in C standard library
|
||||
!define StdUtils.GetMinutes '!insertmacro _StdU_GetMinutes' #GetSystemTimeAsFileTime(), returns the number of minutes
|
||||
!define StdUtils.GetHours '!insertmacro _StdU_GetHours' #GetSystemTimeAsFileTime(), returns the number of hours
|
||||
!define StdUtils.GetDays '!insertmacro _StdU_GetDays' #GetSystemTimeAsFileTime(), returns the number of days
|
||||
!define StdUtils.Rand '!insertmacro _StdU_Rand' #rand(), as in C standard library
|
||||
!define StdUtils.RandMax '!insertmacro _StdU_RandMax' #rand(), as in C standard library, with maximum value
|
||||
!define StdUtils.RandMinMax '!insertmacro _StdU_RandMinMax' #rand(), as in C standard library, with minimum/maximum value
|
||||
!define StdUtils.RandList '!insertmacro _StdU_RandList' #rand(), as in C standard library, with list support
|
||||
!define StdUtils.RandBytes '!insertmacro _StdU_RandBytes' #Generates random bytes, returned as Base64-encoded string
|
||||
!define StdUtils.FormatStr '!insertmacro _StdU_FormatStr' #sprintf(), as in C standard library, one '%d' placeholder
|
||||
!define StdUtils.FormatStr2 '!insertmacro _StdU_FormatStr2' #sprintf(), as in C standard library, two '%d' placeholders
|
||||
!define StdUtils.FormatStr3 '!insertmacro _StdU_FormatStr3' #sprintf(), as in C standard library, three '%d' placeholders
|
||||
!define StdUtils.ScanStr '!insertmacro _StdU_ScanStr' #sscanf(), as in C standard library, one '%d' placeholder
|
||||
!define StdUtils.ScanStr2 '!insertmacro _StdU_ScanStr2' #sscanf(), as in C standard library, two '%d' placeholders
|
||||
!define StdUtils.ScanStr3 '!insertmacro _StdU_ScanStr3' #sscanf(), as in C standard library, three '%d' placeholders
|
||||
!define StdUtils.TrimStr '!insertmacro _StdU_TrimStr' #Remove whitspaces from string, left and right
|
||||
!define StdUtils.TrimStrLeft '!insertmacro _StdU_TrimStrLeft' #Remove whitspaces from string, left side only
|
||||
!define StdUtils.TrimStrRight '!insertmacro _StdU_TrimStrRight' #Remove whitspaces from string, right side only
|
||||
!define StdUtils.RevStr '!insertmacro _StdU_RevStr' #Reverse a string, e.g. "reverse me" <-> "em esrever"
|
||||
!define StdUtils.ValidFileName '!insertmacro _StdU_ValidFileName' #Test whether string is a valid file name - no paths allowed
|
||||
!define StdUtils.ValidPathSpec '!insertmacro _StdU_ValidPathSpec' #Test whether string is a valid full(!) path specification
|
||||
!define StdUtils.ValidDomainName '!insertmacro _StdU_ValidDomain' #Test whether string is a valid host name or domain name
|
||||
!define StdUtils.StrToUtf8 '!insertmacro _StdU_StrToUtf8' #Convert string from Unicode (UTF-16) or ANSI to UTF-8 bytes
|
||||
!define StdUtils.StrFromUtf8 '!insertmacro _StdU_StrFromUtf8' #Convert string from UTF-8 bytes to Unicode (UTF-16) or ANSI
|
||||
!define StdUtils.SHFileMove '!insertmacro _StdU_SHFileMove' #SHFileOperation(), using the FO_MOVE operation
|
||||
!define StdUtils.SHFileCopy '!insertmacro _StdU_SHFileCopy' #SHFileOperation(), using the FO_COPY operation
|
||||
!define StdUtils.AppendToFile '!insertmacro _StdU_AppendToFile' #Append contents of an existing file to another file
|
||||
!define StdUtils.ExecShellAsUser '!insertmacro _StdU_ExecShlUser' #ShellExecute() as NON-elevated user from elevated installer
|
||||
!define StdUtils.InvokeShellVerb '!insertmacro _StdU_InvkeShlVrb' #Invokes a "shell verb", e.g. for pinning items to the taskbar
|
||||
!define StdUtils.ExecShellWaitEx '!insertmacro _StdU_ExecShlWaitEx' #ShellExecuteEx(), returns the handle of the new process
|
||||
!define StdUtils.WaitForProcEx '!insertmacro _StdU_WaitForProcEx' #WaitForSingleObject(), e.g. to wait for a running process
|
||||
!define StdUtils.GetParameter '!insertmacro _StdU_GetParameter' #Get the value of a specific command-line option
|
||||
!define StdUtils.TestParameter '!insertmacro _StdU_TestParameter' #Test whether a specific command-line option has been set
|
||||
!define StdUtils.ParameterCnt '!insertmacro _StdU_ParameterCnt' #Get number of command-line tokens, similar to argc in main()
|
||||
!define StdUtils.ParameterStr '!insertmacro _StdU_ParameterStr' #Get the n-th command-line token, similar to argv[i] in main()
|
||||
!define StdUtils.GetAllParameters '!insertmacro _StdU_GetAllParams' #Get complete command-line, but without executable name
|
||||
!define StdUtils.GetRealOSVersion '!insertmacro _StdU_GetRealOSVer' #Get the *real* Windows version number, even on Windows 8.1+
|
||||
!define StdUtils.GetRealOSBuildNo '!insertmacro _StdU_GetRealOSBld' #Get the *real* Windows build number, even on Windows 8.1+
|
||||
!define StdUtils.GetRealOSName '!insertmacro _StdU_GetRealOSStr' #Get the *real* Windows version, as a "friendly" name
|
||||
!define StdUtils.GetOSEdition '!insertmacro _StdU_GetOSEdition' #Get the Windows edition, i.e. "workstation" or "server"
|
||||
!define StdUtils.GetOSReleaseId '!insertmacro _StdU_GetOSRelIdNo' #Get the Windows release identifier (on Windows 10)
|
||||
!define StdUtils.GetOSReleaseName '!insertmacro _StdU_GetOSRelIdStr' #Get the Windows release (on Windows 10), as a "friendly" name
|
||||
!define StdUtils.VerifyOSVersion '!insertmacro _StdU_VrfyRealOSVer' #Compare *real* operating system to an expected version number
|
||||
!define StdUtils.VerifyOSBuildNo '!insertmacro _StdU_VrfyRealOSBld' #Compare *real* operating system to an expected build number
|
||||
!define StdUtils.HashText '!insertmacro _StdU_HashText' #Compute hash from text string (CRC32, MD5, SHA1/2/3, BLAKE2)
|
||||
!define StdUtils.HashFile '!insertmacro _StdU_HashFile' #Compute hash from file (CRC32, MD5, SHA1/2/3, BLAKE2)
|
||||
!define StdUtils.NormalizePath '!insertmacro _StdU_NormalizePath' #Simplifies the path to produce a direct, well-formed path
|
||||
!define StdUtils.GetParentPath '!insertmacro _StdU_GetParentPath' #Get parent path by removing the last component from the path
|
||||
!define StdUtils.SplitPath '!insertmacro _StdU_SplitPath' #Split the components of the given path
|
||||
!define StdUtils.GetDrivePart '!insertmacro _StdU_GetDrivePart' #Get drive component of path
|
||||
!define StdUtils.GetDirectoryPart '!insertmacro _StdU_GetDirPart' #Get directory component of path
|
||||
!define StdUtils.GetFileNamePart '!insertmacro _StdU_GetFNamePart' #Get file name component of path
|
||||
!define StdUtils.GetExtensionPart '!insertmacro _StdU_GetExtnPart' #Get file extension component of path
|
||||
!define StdUtils.TimerCreate '!insertmacro _StdU_TimerCreate' #Create a new event-timer that will be triggered periodically
|
||||
!define StdUtils.TimerDestroy '!insertmacro _StdU_TimerDestroy' #Destroy a running timer created with TimerCreate()
|
||||
!define StdUtils.ProtectStr '!insertmacro _StdU_PrtctStr' #Protect a given String using Windows' DPAPI
|
||||
!define StdUtils.UnprotectStr '!insertmacro _StdU_UnprtctStr' #Unprotect a string that was protected via ProtectStr()
|
||||
!define StdUtils.GetLibVersion '!insertmacro _StdU_GetLibVersion' #Get the current StdUtils library version (for debugging)
|
||||
!define StdUtils.SetVerbose '!insertmacro _StdU_SetVerbose' #Enable or disable "verbose" mode (for debugging)
|
||||
|
||||
|
||||
#################################################################################
|
||||
# MACRO DEFINITIONS
|
||||
#################################################################################
|
||||
|
||||
!macro _StdU_Time out
|
||||
StdUtils::Time /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetMinutes out
|
||||
StdUtils::GetMinutes /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetHours out
|
||||
StdUtils::GetHours /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetDays out
|
||||
StdUtils::GetDays /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_Rand out
|
||||
StdUtils::Rand /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_RandMax out max
|
||||
push ${max}
|
||||
StdUtils::RandMax /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_RandMinMax out min max
|
||||
push ${min}
|
||||
push ${max}
|
||||
StdUtils::RandMinMax /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_RandList count max
|
||||
push ${max}
|
||||
push ${count}
|
||||
StdUtils::RandList /NOUNLOAD
|
||||
!macroend
|
||||
|
||||
!macro _StdU_RandBytes out count
|
||||
push ${count}
|
||||
StdUtils::RandBytes /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_FormatStr out format val
|
||||
push `${format}`
|
||||
push ${val}
|
||||
StdUtils::FormatStr /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_FormatStr2 out format val1 val2
|
||||
push `${format}`
|
||||
push ${val1}
|
||||
push ${val2}
|
||||
StdUtils::FormatStr2 /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_FormatStr3 out format val1 val2 val3
|
||||
push `${format}`
|
||||
push ${val1}
|
||||
push ${val2}
|
||||
push ${val3}
|
||||
StdUtils::FormatStr3 /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_ScanStr out format input default
|
||||
push `${format}`
|
||||
push `${input}`
|
||||
push ${default}
|
||||
StdUtils::ScanStr /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_ScanStr2 out1 out2 format input default1 default2
|
||||
push `${format}`
|
||||
push `${input}`
|
||||
push ${default1}
|
||||
push ${default2}
|
||||
StdUtils::ScanStr2 /NOUNLOAD
|
||||
pop ${out1}
|
||||
pop ${out2}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_ScanStr3 out1 out2 out3 format input default1 default2 default3
|
||||
push `${format}`
|
||||
push `${input}`
|
||||
push ${default1}
|
||||
push ${default2}
|
||||
push ${default3}
|
||||
StdUtils::ScanStr3 /NOUNLOAD
|
||||
pop ${out1}
|
||||
pop ${out2}
|
||||
pop ${out3}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_TrimStr var
|
||||
push ${var}
|
||||
StdUtils::TrimStr /NOUNLOAD
|
||||
pop ${var}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_TrimStrLeft var
|
||||
push ${var}
|
||||
StdUtils::TrimStrLeft /NOUNLOAD
|
||||
pop ${var}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_TrimStrRight var
|
||||
push ${var}
|
||||
StdUtils::TrimStrRight /NOUNLOAD
|
||||
pop ${var}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_RevStr var
|
||||
push ${var}
|
||||
StdUtils::RevStr /NOUNLOAD
|
||||
pop ${var}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_ValidFileName out test
|
||||
push `${test}`
|
||||
StdUtils::ValidFileName /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_ValidPathSpec out test
|
||||
push `${test}`
|
||||
StdUtils::ValidPathSpec /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_ValidDomain out test
|
||||
push `${test}`
|
||||
StdUtils::ValidDomainName /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
|
||||
!macro _StdU_StrToUtf8 out str
|
||||
push `${str}`
|
||||
StdUtils::StrToUtf8 /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_StrFromUtf8 out trnc str
|
||||
push ${trnc}
|
||||
push `${str}`
|
||||
StdUtils::StrFromUtf8 /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_SHFileMove out from to hwnd
|
||||
push `${from}`
|
||||
push `${to}`
|
||||
push ${hwnd}
|
||||
StdUtils::SHFileMove /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_SHFileCopy out from to hwnd
|
||||
push `${from}`
|
||||
push `${to}`
|
||||
push ${hwnd}
|
||||
StdUtils::SHFileCopy /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_AppendToFile out from dest offset maxlen
|
||||
push `${from}`
|
||||
push `${dest}`
|
||||
push ${offset}
|
||||
push ${maxlen}
|
||||
StdUtils::AppendToFile /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_ExecShlUser out file verb args
|
||||
push `${file}`
|
||||
push `${verb}`
|
||||
push `${args}`
|
||||
StdUtils::ExecShellAsUser /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_InvkeShlVrb out path file verb_id
|
||||
push "${path}"
|
||||
push "${file}"
|
||||
push ${verb_id}
|
||||
StdUtils::InvokeShellVerb /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_ExecShlWaitEx out_res out_val file verb args
|
||||
push `${file}`
|
||||
push `${verb}`
|
||||
push `${args}`
|
||||
StdUtils::ExecShellWaitEx /NOUNLOAD
|
||||
pop ${out_res}
|
||||
pop ${out_val}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_WaitForProcEx out handle
|
||||
push `${handle}`
|
||||
StdUtils::WaitForProcEx /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetParameter out name default
|
||||
push `${name}`
|
||||
push `${default}`
|
||||
StdUtils::GetParameter /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_TestParameter out name
|
||||
push `${name}`
|
||||
StdUtils::TestParameter /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_ParameterCnt out
|
||||
StdUtils::ParameterCnt /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_ParameterStr out index
|
||||
push ${index}
|
||||
StdUtils::ParameterStr /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetAllParams out truncate
|
||||
push `${truncate}`
|
||||
StdUtils::GetAllParameters /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetRealOSVer out_major out_minor out_spack
|
||||
StdUtils::GetRealOsVersion /NOUNLOAD
|
||||
pop ${out_major}
|
||||
pop ${out_minor}
|
||||
pop ${out_spack}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetRealOSBld out
|
||||
StdUtils::GetRealOsBuildNo /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetRealOSStr out
|
||||
StdUtils::GetRealOsName /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_VrfyRealOSVer out major minor spack
|
||||
push `${major}`
|
||||
push `${minor}`
|
||||
push `${spack}`
|
||||
StdUtils::VerifyRealOsVersion /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_VrfyRealOSBld out build
|
||||
push `${build}`
|
||||
StdUtils::VerifyRealOsBuildNo /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetOSEdition out
|
||||
StdUtils::GetOsEdition /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetOSRelIdNo out
|
||||
StdUtils::GetOsReleaseId /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetOSRelIdStr out
|
||||
StdUtils::GetOsReleaseName /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_HashText out type text
|
||||
push `${type}`
|
||||
push `${text}`
|
||||
StdUtils::HashText /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_HashFile out type file
|
||||
push `${type}`
|
||||
push `${file}`
|
||||
StdUtils::HashFile /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_NormalizePath out path
|
||||
push `${path}`
|
||||
StdUtils::NormalizePath /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetParentPath out path
|
||||
push `${path}`
|
||||
StdUtils::GetParentPath /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_SplitPath out_drive out_dir out_fname out_ext path
|
||||
push `${path}`
|
||||
StdUtils::SplitPath /NOUNLOAD
|
||||
pop ${out_drive}
|
||||
pop ${out_dir}
|
||||
pop ${out_fname}
|
||||
pop ${out_ext}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetDrivePart out path
|
||||
push `${path}`
|
||||
StdUtils::GetDrivePart /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetDirPart out path
|
||||
push `${path}`
|
||||
StdUtils::GetDirectoryPart /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetFNamePart out path
|
||||
push `${path}`
|
||||
StdUtils::GetFileNamePart /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetExtnPart out path
|
||||
push `${path}`
|
||||
StdUtils::GetExtensionPart /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_TimerCreate out callback interval
|
||||
GetFunctionAddress ${out} ${callback}
|
||||
push ${out}
|
||||
push ${interval}
|
||||
StdUtils::TimerCreate /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_TimerDestroy out timer_id
|
||||
push ${timer_id}
|
||||
StdUtils::TimerDestroy /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_PrtctStr out dpsc salt text
|
||||
push `${dpsc}`
|
||||
push `${salt}`
|
||||
push `${text}`
|
||||
StdUtils::ProtectStr /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_UnprtctStr out trnc salt data
|
||||
push `${trnc}`
|
||||
push `${salt}`
|
||||
push `${data}`
|
||||
StdUtils::UnprotectStr /NOUNLOAD
|
||||
pop ${out}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_GetLibVersion out_ver out_tst
|
||||
StdUtils::GetLibVersion /NOUNLOAD
|
||||
pop ${out_ver}
|
||||
pop ${out_tst}
|
||||
!macroend
|
||||
|
||||
!macro _StdU_SetVerbose enable
|
||||
Push ${enable}
|
||||
StdUtils::SetVerboseMode /NOUNLOAD
|
||||
!macroend
|
||||
|
||||
|
||||
#################################################################################
|
||||
# MAGIC NUMBERS
|
||||
#################################################################################
|
||||
|
||||
!define StdUtils.Const.ShellVerb.PinToTaskbar 0
|
||||
!define StdUtils.Const.ShellVerb.UnpinFromTaskbar 1
|
||||
!define StdUtils.Const.ShellVerb.PinToStart 2
|
||||
!define StdUtils.Const.ShellVerb.UnpinFromStart 3
|
||||
|
||||
!endif # !___STDUTILS__NSH___
|
||||
28
builder/win/nsis/Include/nsProcess.nsh
Normal file
28
builder/win/nsis/Include/nsProcess.nsh
Normal file
@@ -0,0 +1,28 @@
|
||||
!define nsProcess::FindProcess `!insertmacro nsProcess::FindProcess`
|
||||
|
||||
!macro nsProcess::FindProcess _FILE _ERR
|
||||
nsProcess::_FindProcess /NOUNLOAD `${_FILE}`
|
||||
Pop ${_ERR}
|
||||
!macroend
|
||||
|
||||
|
||||
!define nsProcess::KillProcess `!insertmacro nsProcess::KillProcess`
|
||||
|
||||
!macro nsProcess::KillProcess _FILE _ERR
|
||||
nsProcess::_KillProcess /NOUNLOAD `${_FILE}`
|
||||
Pop ${_ERR}
|
||||
!macroend
|
||||
|
||||
!define nsProcess::CloseProcess `!insertmacro nsProcess::CloseProcess`
|
||||
|
||||
!macro nsProcess::CloseProcess _FILE _ERR
|
||||
nsProcess::_CloseProcess /NOUNLOAD `${_FILE}`
|
||||
Pop ${_ERR}
|
||||
!macroend
|
||||
|
||||
|
||||
!define nsProcess::Unload `!insertmacro nsProcess::Unload`
|
||||
|
||||
!macro nsProcess::Unload
|
||||
nsProcess::_Unload
|
||||
!macroend
|
||||
53
builder/win/nsis/Include/registerExtension.nsh
Normal file
53
builder/win/nsis/Include/registerExtension.nsh
Normal file
@@ -0,0 +1,53 @@
|
||||
!define registerExtension "!insertmacro registerExtension"
|
||||
!define unregisterExtension "!insertmacro unregisterExtension"
|
||||
!define SHCNE_ASSOCCHANGED 0x8000000
|
||||
!define SHCNF_IDLIST 0
|
||||
|
||||
; Source = http://nsis.sourceforge.net/File_Association
|
||||
; Patched for SABnzbd by swi-tch
|
||||
|
||||
!macro registerExtension icon executable extension description
|
||||
Push "${icon}" ; "full path to icon.ico"
|
||||
Push "${executable}" ; "full path to my.exe"
|
||||
Push "${extension}" ; ".mkv"
|
||||
Push "${description}" ; "MKV File"
|
||||
Call registerExtension
|
||||
!macroend
|
||||
|
||||
; back up old value of .opt
|
||||
Function registerExtension
|
||||
!define Index "Line${__LINE__}"
|
||||
pop $R0 ; ext name
|
||||
pop $R1
|
||||
pop $R2
|
||||
pop $R3
|
||||
push $1
|
||||
push $0
|
||||
DeleteRegKey HKEY_CURRENT_USER "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$R1"
|
||||
WriteRegStr HKCR $R1 "" $R0
|
||||
WriteRegStr HKCR $R0 "" $R0
|
||||
WriteRegStr HKCR "$R0\shell" "" "open"
|
||||
WriteRegStr HKCR "$R0\DefaultIcon" "" "$R3,0"
|
||||
WriteRegStr HKCR "$R0\shell\open\command" "" '"$R2" "%1"'
|
||||
WriteRegStr HKCR "$R0\shell\edit" "" "Edit $R0"
|
||||
WriteRegStr HKCR "$R0\shell\edit\command" "" '"$R2" "%1"'
|
||||
pop $0
|
||||
pop $1
|
||||
!undef Index
|
||||
System::Call 'Shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_IDLIST}, i 0, i 0)'
|
||||
FunctionEnd
|
||||
|
||||
!macro unregisterExtension extension description
|
||||
Push "${extension}" ; ".mkv"
|
||||
Push "${description}" ; "MKV File"
|
||||
Call un.unregisterExtension
|
||||
!macroend
|
||||
|
||||
Function un.unregisterExtension
|
||||
pop $R1 ; description
|
||||
pop $R0 ; extension
|
||||
!define Index "Line${__LINE__}"
|
||||
DeleteRegKey HKCR $R0
|
||||
!undef Index
|
||||
System::Call 'Shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_IDLIST}, i 0, i 0)'
|
||||
FunctionEnd
|
||||
411
builder/win/nsis/Include/servicelib.nsh
Normal file
411
builder/win/nsis/Include/servicelib.nsh
Normal file
@@ -0,0 +1,411 @@
|
||||
; NSIS SERVICE LIBRARY - servicelib.nsh
|
||||
; Version 1.8.1 - Jun 21th, 2013
|
||||
; Questions/Comments - dselkirk@hotmail.com
|
||||
;
|
||||
; Description:
|
||||
; Provides an interface to window services
|
||||
;
|
||||
; Inputs:
|
||||
; action - systemlib action ie. create, delete, start, stop, pause,
|
||||
; continue, installed, running, status
|
||||
; name - name of service to manipulate
|
||||
; param - action parameters; usage: var1=value1;var2=value2;...etc.
|
||||
; (don't forget to add a ';' after the last value!)
|
||||
;
|
||||
; Actions:
|
||||
; create - creates a new windows service
|
||||
; Parameters:
|
||||
; path - path to service executable
|
||||
; autostart - automatically start with system ie. 1|0
|
||||
; interact - interact with the desktop ie. 1|0
|
||||
; depend - service dependencies
|
||||
; user - user that runs the service
|
||||
; password - password of the above user
|
||||
; display - display name in service's console
|
||||
; description - Description of service
|
||||
; starttype - start type (supersedes autostart)
|
||||
; servicetype - service type (supersedes interact)
|
||||
;
|
||||
; delete - deletes a windows service
|
||||
; start - start a stopped windows service
|
||||
; stop - stops a running windows service
|
||||
; pause - pauses a running windows service
|
||||
; continue - continues a paused windows service
|
||||
; installed - is the provided service installed
|
||||
; Parameters:
|
||||
; action - if true then invokes the specified action
|
||||
; running - is the provided service running
|
||||
; Parameters:
|
||||
; action - if true then invokes the specified action
|
||||
; status - check the status of the provided service
|
||||
;
|
||||
; Usage:
|
||||
; Method 1:
|
||||
; Push "action"
|
||||
; Push "name"
|
||||
; Push "param"
|
||||
; Call Service
|
||||
; Pop $0 ;response
|
||||
;
|
||||
; Method 2:
|
||||
; !insertmacro SERVICE "action" "name" "param"
|
||||
;
|
||||
; History:
|
||||
; 1.0 - 09/15/2003 - Initial release
|
||||
; 1.1 - 09/16/2003 - Changed &l to i, thx brainsucker
|
||||
; 1.2 - 02/29/2004 - Fixed documentation.
|
||||
; 1.3 - 01/05/2006 - Fixed interactive flag and pop order (Kichik)
|
||||
; 1.4 - 12/07/2006 - Added display and depend, fixed datatypes (Vitoco)
|
||||
; 1.5 - 06/25/2008 - Added description of service.(DeSafe.com/liuqixing#gmail.com)
|
||||
; 1.5.1 - 06/12/2009 - Added use of __UNINSTALL__
|
||||
; 1.6 - 08/02/2010 - Fixed description implementation (Anders)
|
||||
; 1.7 - 04/11/2010 - Added get running service process id (Nico)
|
||||
; 1.8 - 24/03/2011 - Added starttype and servicetype (Sergius)
|
||||
; 1.8.1 - 21/06/2013 - Added dynamic ASCII & Unicode support (Zinthose)
|
||||
|
||||
!ifndef SERVICELIB
|
||||
!define SERVICELIB
|
||||
|
||||
!define SC_MANAGER_ALL_ACCESS 0x3F
|
||||
!define SC_STATUS_PROCESS_INFO 0x0
|
||||
!define SERVICE_ALL_ACCESS 0xF01FF
|
||||
|
||||
!define SERVICE_CONTROL_STOP 1
|
||||
!define SERVICE_CONTROL_PAUSE 2
|
||||
!define SERVICE_CONTROL_CONTINUE 3
|
||||
|
||||
!define SERVICE_STOPPED 0x1
|
||||
!define SERVICE_START_PENDING 0x2
|
||||
!define SERVICE_STOP_PENDING 0x3
|
||||
!define SERVICE_RUNNING 0x4
|
||||
!define SERVICE_CONTINUE_PENDING 0x5
|
||||
!define SERVICE_PAUSE_PENDING 0x6
|
||||
!define SERVICE_PAUSED 0x7
|
||||
|
||||
!define SERVICE_KERNEL_DRIVER 0x00000001
|
||||
!define SERVICE_FILE_SYSTEM_DRIVER 0x00000002
|
||||
!define SERVICE_WIN32_OWN_PROCESS 0x00000010
|
||||
!define SERVICE_WIN32_SHARE_PROCESS 0x00000020
|
||||
!define SERVICE_INTERACTIVE_PROCESS 0x00000100
|
||||
|
||||
|
||||
!define SERVICE_BOOT_START 0x00000000
|
||||
!define SERVICE_SYSTEM_START 0x00000001
|
||||
!define SERVICE_AUTO_START 0x00000002
|
||||
!define SERVICE_DEMAND_START 0x00000003
|
||||
!define SERVICE_DISABLED 0x00000004
|
||||
|
||||
## Added by Zinthose for Native Unicode Support
|
||||
!ifdef NSIS_UNICODE
|
||||
!define APITAG "W"
|
||||
!else
|
||||
!define APITAG "A"
|
||||
!endif
|
||||
|
||||
!macro SERVICE ACTION NAME PARAM
|
||||
Push '${ACTION}'
|
||||
Push '${NAME}'
|
||||
Push '${PARAM}'
|
||||
!ifdef __UNINSTALL__
|
||||
Call un.Service
|
||||
!else
|
||||
Call Service
|
||||
!endif
|
||||
!macroend
|
||||
|
||||
!macro FUNC_GETPARAM
|
||||
Push $0
|
||||
Push $1
|
||||
Push $2
|
||||
Push $3
|
||||
Push $4
|
||||
Push $5
|
||||
Push $6
|
||||
Push $7
|
||||
Exch 8
|
||||
Pop $1 ;name
|
||||
Exch 8
|
||||
Pop $2 ;source
|
||||
StrCpy $0 ""
|
||||
StrLen $7 $2
|
||||
StrCpy $3 0
|
||||
lbl_loop:
|
||||
IntCmp $3 $7 0 0 lbl_done
|
||||
StrLen $4 "$1="
|
||||
StrCpy $5 $2 $4 $3
|
||||
StrCmp $5 "$1=" 0 lbl_next
|
||||
IntOp $5 $3 + $4
|
||||
StrCpy $3 $5
|
||||
lbl_loop2:
|
||||
IntCmp $3 $7 0 0 lbl_done
|
||||
StrCpy $6 $2 1 $3
|
||||
StrCmp $6 ";" 0 lbl_next2
|
||||
IntOp $6 $3 - $5
|
||||
StrCpy $0 $2 $6 $5
|
||||
Goto lbl_done
|
||||
lbl_next2:
|
||||
IntOp $3 $3 + 1
|
||||
Goto lbl_loop2
|
||||
lbl_next:
|
||||
IntOp $3 $3 + 1
|
||||
Goto lbl_loop
|
||||
lbl_done:
|
||||
Pop $5
|
||||
Pop $4
|
||||
Pop $3
|
||||
Pop $2
|
||||
Pop $1
|
||||
Exch 2
|
||||
Pop $6
|
||||
Pop $7
|
||||
Exch $0
|
||||
!macroend
|
||||
|
||||
!macro CALL_GETPARAM VAR NAME DEFAULT LABEL
|
||||
Push $1
|
||||
Push ${NAME}
|
||||
Call ${UN}GETPARAM
|
||||
Pop $6
|
||||
StrCpy ${VAR} "${DEFAULT}"
|
||||
StrCmp $6 "" "${LABEL}" 0
|
||||
StrCpy ${VAR} $6
|
||||
!macroend
|
||||
|
||||
!macro FUNC_SERVICE UN
|
||||
Push $0
|
||||
Push $1
|
||||
Push $2
|
||||
Push $3
|
||||
Push $4
|
||||
Push $5
|
||||
Push $6
|
||||
Push $7
|
||||
Exch 8
|
||||
Pop $1 ;param
|
||||
Exch 8
|
||||
Pop $2 ;name
|
||||
Exch 8
|
||||
Pop $3 ;action
|
||||
;$0 return
|
||||
;$4 OpenSCManager
|
||||
;$5 OpenService
|
||||
|
||||
StrCpy $0 "false"
|
||||
System::Call 'advapi32::OpenSCManager${APITAG}(n, n, i ${SC_MANAGER_ALL_ACCESS}) i.r4'
|
||||
IntCmp $4 0 lbl_done
|
||||
StrCmp $3 "create" lbl_create
|
||||
System::Call 'advapi32::OpenService${APITAG}(i r4, t r2, i ${SERVICE_ALL_ACCESS}) i.r5'
|
||||
IntCmp $5 0 lbl_done
|
||||
|
||||
lbl_select:
|
||||
StrCmp $3 "delete" lbl_delete
|
||||
StrCmp $3 "start" lbl_start
|
||||
StrCmp $3 "stop" lbl_stop
|
||||
StrCmp $3 "pause" lbl_pause
|
||||
StrCmp $3 "continue" lbl_continue
|
||||
StrCmp $3 "installed" lbl_installed
|
||||
StrCmp $3 "running" lbl_running
|
||||
StrCmp $3 "status" lbl_status
|
||||
StrCmp $3 "processid" lbl_processid
|
||||
Goto lbl_done
|
||||
|
||||
; create service
|
||||
lbl_create:
|
||||
Push $R1 ;depend
|
||||
Push $R2 ;user
|
||||
Push $R3 ;password
|
||||
Push $R4 ;servicetype/interact
|
||||
Push $R5 ;starttype/autostart
|
||||
Push $R6 ;path
|
||||
Push $R7 ;display
|
||||
Push $R8 ;description
|
||||
|
||||
!insertmacro CALL_GETPARAM $R1 "depend" "n" "lbl_depend"
|
||||
StrCpy $R1 't "$R1"'
|
||||
lbl_depend:
|
||||
StrCmp $R1 "n" 0 lbl_machine ;old name of depend param
|
||||
!insertmacro CALL_GETPARAM $R1 "machine" "n" "lbl_machine"
|
||||
StrCpy $R1 't "$R1"'
|
||||
lbl_machine:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R2 "user" "n" "lbl_user"
|
||||
StrCpy $R2 't "$R2"'
|
||||
lbl_user:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R3 "password" "n" "lbl_password"
|
||||
StrCpy $R3 't "$R3"'
|
||||
lbl_password:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R4 "interact" "${SERVICE_WIN32_OWN_PROCESS}" "lbl_interact"
|
||||
StrCpy $6 ${SERVICE_WIN32_OWN_PROCESS}
|
||||
IntCmp $R4 0 +2
|
||||
IntOp $6 $6 | ${SERVICE_INTERACTIVE_PROCESS}
|
||||
StrCpy $R4 $6
|
||||
lbl_interact:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R4 "servicetype" "$R4" "lbl_servicetype"
|
||||
lbl_servicetype:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R5 "autostart" "${SERVICE_DEMAND_START}" "lbl_autostart"
|
||||
StrCpy $6 ${SERVICE_DEMAND_START}
|
||||
IntCmp $R5 0 +2
|
||||
StrCpy $6 ${SERVICE_AUTO_START}
|
||||
StrCpy $R5 $6
|
||||
lbl_autostart:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R5 "starttype" "$R5" "lbl_starttype"
|
||||
lbl_starttype:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R6 "path" "n" "lbl_path"
|
||||
lbl_path:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R7 "display" "$2" "lbl_display"
|
||||
lbl_display:
|
||||
|
||||
!insertmacro CALL_GETPARAM $R8 "description" "$2" "lbl_description"
|
||||
lbl_description:
|
||||
|
||||
System::Call 'advapi32::CreateService${APITAG}(i r4, t r2, t R7, i ${SERVICE_ALL_ACCESS}, \
|
||||
i R4, i R5, i 0, t R6, n, n, $R1, $R2, $R3) i.r6'
|
||||
|
||||
; write description of service (SERVICE_CONFIG_DESCRIPTION)
|
||||
System::Call 'advapi32::ChangeServiceConfig2${APITAG}(ir6,i1,*t "$R8")i.R7'
|
||||
strcmp $R7 "error" 0 lbl_descriptioncomplete
|
||||
WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\$2" "Description" $R8
|
||||
lbl_descriptioncomplete:
|
||||
|
||||
Pop $R8
|
||||
Pop $R7
|
||||
Pop $R6
|
||||
Pop $R5
|
||||
Pop $R4
|
||||
Pop $R3
|
||||
Pop $R2
|
||||
Pop $R1
|
||||
StrCmp $6 0 lbl_done lbl_good
|
||||
|
||||
; delete service
|
||||
lbl_delete:
|
||||
System::Call 'advapi32::DeleteService(i r5) i.r6'
|
||||
StrCmp $6 0 lbl_done lbl_good
|
||||
|
||||
; start service
|
||||
lbl_start:
|
||||
System::Call 'advapi32::StartService${APITAG}(i r5, i 0, i 0) i.r6'
|
||||
StrCmp $6 0 lbl_done lbl_good
|
||||
|
||||
; stop service
|
||||
lbl_stop:
|
||||
Push $R1
|
||||
System::Call '*(i,i,i,i,i,i,i) i.R1'
|
||||
System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_STOP}, i $R1) i'
|
||||
System::Free $R1
|
||||
Pop $R1
|
||||
StrCmp $6 0 lbl_done lbl_good
|
||||
|
||||
; pause service
|
||||
lbl_pause:
|
||||
Push $R1
|
||||
System::Call '*(i,i,i,i,i,i,i) i.R1'
|
||||
System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_PAUSE}, i $R1) i'
|
||||
System::Free $R1
|
||||
Pop $R1
|
||||
StrCmp $6 0 lbl_done lbl_good
|
||||
|
||||
; continue service
|
||||
lbl_continue:
|
||||
Push $R1
|
||||
System::Call '*(i,i,i,i,i,i,i) i.R1'
|
||||
System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_CONTINUE}, i $R1) i'
|
||||
System::Free $R1
|
||||
Pop $R1
|
||||
StrCmp $6 0 lbl_done lbl_good
|
||||
|
||||
; is installed
|
||||
lbl_installed:
|
||||
!insertmacro CALL_GETPARAM $7 "action" "" "lbl_good"
|
||||
StrCpy $3 $7
|
||||
Goto lbl_select
|
||||
|
||||
; is service running
|
||||
lbl_running:
|
||||
Push $R1
|
||||
System::Call '*(i,i,i,i,i,i,i) i.R1'
|
||||
System::Call 'advapi32::QueryServiceStatus(i r5, i $R1) i'
|
||||
System::Call '*$R1(i, i.r6)'
|
||||
System::Free $R1
|
||||
Pop $R1
|
||||
IntFmt $6 "0x%X" $6
|
||||
StrCmp $6 ${SERVICE_RUNNING} 0 lbl_done
|
||||
!insertmacro CALL_GETPARAM $7 "action" "" "lbl_good"
|
||||
StrCpy $3 $7
|
||||
Goto lbl_select
|
||||
|
||||
lbl_status:
|
||||
Push $R1
|
||||
System::Call '*(i,i,i,i,i,i,i) i.R1'
|
||||
System::Call 'advapi32::QueryServiceStatus(i r5, i $R1) i'
|
||||
System::Call '*$R1(i, i .r6)'
|
||||
System::Free $R1
|
||||
Pop $R1
|
||||
IntFmt $6 "0x%X" $6
|
||||
StrCpy $0 "running"
|
||||
IntCmp $6 ${SERVICE_RUNNING} lbl_done
|
||||
StrCpy $0 "stopped"
|
||||
IntCmp $6 ${SERVICE_STOPPED} lbl_done
|
||||
StrCpy $0 "start_pending"
|
||||
IntCmp $6 ${SERVICE_START_PENDING} lbl_done
|
||||
StrCpy $0 "stop_pending"
|
||||
IntCmp $6 ${SERVICE_STOP_PENDING} lbl_done
|
||||
StrCpy $0 "running"
|
||||
IntCmp $6 ${SERVICE_RUNNING} lbl_done
|
||||
StrCpy $0 "continue_pending"
|
||||
IntCmp $6 ${SERVICE_CONTINUE_PENDING} lbl_done
|
||||
StrCpy $0 "pause_pending"
|
||||
IntCmp $6 ${SERVICE_PAUSE_PENDING} lbl_done
|
||||
StrCpy $0 "paused"
|
||||
IntCmp $6 ${SERVICE_PAUSED} lbl_done
|
||||
StrCpy $0 "unknown"
|
||||
Goto lbl_done
|
||||
|
||||
lbl_processid:
|
||||
Push $R1
|
||||
Push $R2
|
||||
System::Call '*(i,i,i,i,i,i,i,i,i) i.R1'
|
||||
System::Call '*(i 0) i.R2'
|
||||
System::Call "advapi32::QueryServiceStatusEx(i r5, i ${SC_STATUS_PROCESS_INFO}, i $R1, i 36, i $R2) i"
|
||||
System::Call "*$R1(i,i,i,i,i,i,i, i .r0)"
|
||||
System::Free $R2
|
||||
System::Free $R1
|
||||
Pop $R2
|
||||
Pop $R1
|
||||
Goto lbl_done
|
||||
|
||||
lbl_good:
|
||||
StrCpy $0 "true"
|
||||
lbl_done:
|
||||
IntCmp $5 0 +2
|
||||
System::Call 'advapi32::CloseServiceHandle(i r5) n'
|
||||
IntCmp $4 0 +2
|
||||
System::Call 'advapi32::CloseServiceHandle(i r4) n'
|
||||
Pop $4
|
||||
Pop $3
|
||||
Pop $2
|
||||
Pop $1
|
||||
Exch 3
|
||||
Pop $5
|
||||
Pop $7
|
||||
Pop $6
|
||||
Exch $0
|
||||
!macroend
|
||||
|
||||
Function Service
|
||||
!insertmacro FUNC_SERVICE ""
|
||||
FunctionEnd
|
||||
|
||||
Function GetParam
|
||||
!insertmacro FUNC_GETPARAM
|
||||
FunctionEnd
|
||||
|
||||
!undef APITAG
|
||||
!endif
|
||||
BIN
builder/win/nsis/Plugins/StdUtils.dll
Normal file
BIN
builder/win/nsis/Plugins/StdUtils.dll
Normal file
Binary file not shown.
BIN
builder/win/nsis/Plugins/liteFirewallW.dll
Normal file
BIN
builder/win/nsis/Plugins/liteFirewallW.dll
Normal file
Binary file not shown.
BIN
builder/win/nsis/Plugins/nsProcess.dll
Normal file
BIN
builder/win/nsis/Plugins/nsProcess.dll
Normal file
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
##
|
||||
## Bad URL Fetch Email template for SABnzbd
|
||||
## This a Cheetah template
|
||||
## Documentation: http://sabnzbd.wikidot.com/email-templates
|
||||
## Documentation: https://sabnzbd.org/wiki/extra/email-templates
|
||||
##
|
||||
## Newlines and whitespace are significant!
|
||||
##
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
##
|
||||
## Default Email template for SABnzbd
|
||||
## This a Cheetah template
|
||||
## Documentation: http://sabnzbd.wikidot.com/email-templates
|
||||
## Documentation: https://sabnzbd.org/wiki/extra/email-templates
|
||||
##
|
||||
## Newlines and whitespace are significant!
|
||||
##
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
##
|
||||
## RSS Email template for SABnzbd
|
||||
## This a Cheetah template
|
||||
## Documentation: http://sabnzbd.wikidot.com/email-templates
|
||||
## Documentation: https://sabnzbd.org/wiki/extra/email-templates
|
||||
##
|
||||
## Newlines and whitespace are significant!
|
||||
##
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
<div class="modal-body">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<!--#if not $nt#-->
|
||||
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" id="show_hidden_folders"> <span>$T('systemFolders')</span>
|
||||
<input type="checkbox" id="show_hidden_folders"> <span>$T('hiddenFolders')</span>
|
||||
</label>
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
|
||||
<button type="button" class="btn btn-danger" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> $T('cancel')</button>
|
||||
<button type="button" class="btn btn-default" id="filebrowser_modal_accept"><span class="glyphicon glyphicon-ok"></span> $T('rss-accept')</button>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#set global $root = '../../'#
|
||||
#end if#
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="$active_lang">
|
||||
<html lang="$active_lang" #if $rtl#dir="rtl"#end if#>
|
||||
<head>
|
||||
<title>
|
||||
SABnzbd $T('menu-config')
|
||||
@@ -34,6 +34,9 @@
|
||||
<link rel="stylesheet" type="text/css" href="${root}staticcfg/bootstrap/css/bootstrap.min.css?v=$version" />
|
||||
<link rel="stylesheet" type="text/css" href="${root}staticcfg/css/chartist.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="${root}staticcfg/css/style.css?v=$version" />
|
||||
<!--#if $color_scheme not in ('Light', '') #-->
|
||||
<link rel="stylesheet" type="text/css" href="${root}staticcfg/css/${color_scheme}.css?v=$version"/>
|
||||
<!--#end if#-->
|
||||
|
||||
<link rel="shortcut icon" href="${root}staticcfg/ico/favicon.ico?v=$version" />
|
||||
|
||||
@@ -62,32 +65,12 @@
|
||||
configTranslate.confirmLeave = "$T('confirmWithoutSavingPrompt')";
|
||||
configTranslate.searchPages = ['$T('cmenu-general')', '$T('cmenu-folders')', '$T('cmenu-switches')', '$T('cmenu-sorting')', '$T('cmenu-notif')', '$T('cmenu-special')']
|
||||
</script>
|
||||
<script type="text/javascript" src="${root}staticcfg/js/jquery-3.2.1.min.js?v=$version"></script>
|
||||
<script type="text/javascript" src="${root}staticcfg/js/jquery-3.5.1.min.js?v=$version"></script>
|
||||
<script type="text/javascript" src="${root}staticcfg/bootstrap/js/bootstrap.min.js?v=$version"></script>
|
||||
<script type="text/javascript" src="${root}staticcfg/js/script.js?v=$version"></script>
|
||||
<script type="text/javascript">
|
||||
// Set default functions for the autocomplete everywhere
|
||||
\$.extend(\$.fn.typeahead.defaults, {
|
||||
source: function (query, process) {
|
||||
// If there's no seperator, it must be a relative path
|
||||
if(query.split(folderSeperator).length < 2 && this.\$element.data('initialdir')) {
|
||||
query = this.\$element.data('initialdir') + folderSeperator + query;
|
||||
}
|
||||
// Get info from the API
|
||||
return \$.get(folderBrowseUrl + '&compact=1&term=' + query, function (data) {
|
||||
return process(data);
|
||||
});
|
||||
},
|
||||
updater: function(item) {
|
||||
// Is it a relative path?
|
||||
if(item.indexOf(this.\$element.data('initialdir')) === 0) {
|
||||
// Remove start
|
||||
return item.replace(this.\$element.data('initialdir')+folderSeperator, '');
|
||||
}
|
||||
// Full path
|
||||
return item
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// to top right away
|
||||
if(window.location.hash) {
|
||||
@@ -109,7 +92,7 @@
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
|
||||
<a class="navbar-logo navbar-logo-small" href="${root}" title="$T('Home')">
|
||||
<a class="navbar-logo navbar-logo-small" href="${root}" title="$T('Home')" data-placement="bottom">
|
||||
#include $webdir + "/staticcfg/images/logo-small.svg"#
|
||||
</a>
|
||||
</div>
|
||||
@@ -181,7 +164,7 @@
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="$helpuri$help_uri" target="_blank">
|
||||
<a href="$help_uri" target="_blank">
|
||||
<span class="glyphicon glyphicon-question-sign"></span>
|
||||
<strong>$T('menu-help')</strong>
|
||||
</a>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Config"#-->
|
||||
<!--#set global $help_uri="configuration/3.0/configure"#-->
|
||||
<!--#set global $help_uri = $confighelpuri + "configure"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<!--#from sabnzbd.encoding import CODEPAGE#-->
|
||||
@@ -9,7 +9,7 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">$T('version'): </th>
|
||||
<td>$version [$build]</td>
|
||||
<td>$version [<a href="https://github.com/sabnzbd/sabnzbd/commit/$build" target="_blank">$build</a>]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">$T('uptime'): </th>
|
||||
@@ -25,59 +25,31 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">$T('pythonVersion'): </th>
|
||||
<td>$sys.version[:120] [$CODEPAGE]</td>
|
||||
<td>$sys.version [$CODEPAGE]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">OpenSSL:</th>
|
||||
<td>
|
||||
$ssl_version
|
||||
</td>
|
||||
<td>$ssl_version</td>
|
||||
</tr>
|
||||
<!--#if not $certificate_validation#-->
|
||||
<!--#if not $windows and not $macos#-->
|
||||
<tr>
|
||||
<th scope="row"></th>
|
||||
<th scope="row">Par2cmdline-turbo:</th>
|
||||
<td>
|
||||
<span class="label label-danger">$T('warning')</span> $T('explain-nosslcontext')
|
||||
</td>
|
||||
</tr>
|
||||
<!--#end if#-->
|
||||
<!--#if not $nt and not $darwin#-->
|
||||
<tr>
|
||||
<th scope="row">$T('opt-multicore-par2')</th>
|
||||
<td>
|
||||
<!--#if $have_mt_par2#-->
|
||||
<!--#if $have_par2_turbo#-->
|
||||
<span class="glyphicon glyphicon-ok"></span>
|
||||
<!--#else#-->
|
||||
<span class="label label-warning">$T('notAvailable')</span> $T('explain-getpar2mt')
|
||||
<a href="${helpuri}installation/multicore-par2" target="_blank">${helpuri}installation/multicore-par2</a>
|
||||
<span class="label label-warning">$T('notAvailable')</span> $T('explain-getpar2turbo')<br>
|
||||
<a href="https://sabnzbd.org/wiki/installation/par2cmdline-turbo" target="_blank">https://sabnzbd.org/wiki/installation/par2cmdline-turbo</a>
|
||||
<!--#end if#-->
|
||||
</td>
|
||||
</tr>
|
||||
<!--#end if#-->
|
||||
<!--#if not $have_sabyenc#-->
|
||||
<tr>
|
||||
<th scope="row">SABYenc:</th>
|
||||
<td>
|
||||
<span class="label label-danger">$T('notAvailable')</span>
|
||||
<a href="$helpuri$help_uri#no_sabyenc" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
<!--#end if#-->
|
||||
<!--#if not $have_unzip and not $have_7zip #-->
|
||||
<tr>
|
||||
<th scope="row">$T('opt-enable_unzip'):</th>
|
||||
<td>
|
||||
<span class="label label-warning">$T('notAvailable')</span>
|
||||
<a href="${helpuri}installation/install-off-modules#toc8" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
<!--#end if#-->
|
||||
<!--#if not $have_7zip #-->
|
||||
<tr>
|
||||
<th scope="row">$T('opt-enable_7zip'):</th>
|
||||
<td>
|
||||
<span class="label label-warning">$T('notAvailable')</span>
|
||||
<a href="${helpuri}installation/install-off-modules#toc8" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
|
||||
<a href="https://sabnzbd.org/wiki/installation/install-off-modules#toc8" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
<!--#end if#-->
|
||||
@@ -106,8 +78,8 @@
|
||||
<td><a href="https://github.com/sabnzbd/sabnzbd" target="_blank">https://github.com/sabnzbd/sabnzbd</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">$T('menu-irc') </th>
|
||||
<td><a href="irc://irc.synirc.net/#sabnzbd"><i>#sabnzbd</i> on <i>irc.synirc.net</i></a> $T('or') (<a href="http://sabnzbd.org/live-chat/" target="_blank">webchat</a>)</td>
|
||||
<th scope="row">$T('menu-live-chat') </th>
|
||||
<td><a href="https://sabnzbd.org/live-chat/" target="_blank">https://sabnzbd.org/live-chat/</a> (IRC & Discord)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">$T('menu-issues') </th>
|
||||
@@ -123,8 +95,8 @@
|
||||
</div>
|
||||
|
||||
<div class="colmask">
|
||||
<div class="padding alt">
|
||||
<h5 class="copyright">Copyright © 2007-2020 The SABnzbd Team <<a href="mailto:team@sabnzbd.org">team@sabnzbd.org</a>></h5>
|
||||
<div class="padding">
|
||||
<h5 class="copyright">Copyright © 2007-2025 by The SABnzbd-Team (<a href="https://sabnzbd.org/" target="_blank">sabnzbd.org</a>)</h5>
|
||||
<p class="copyright"><small>$T('yourRights')</small></p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
<!--#set global $pane="Categories"#-->
|
||||
<!--#set global $help_uri="configuration/3.0/categories"#-->
|
||||
<!--#set global $help_uri = $confighelpuri + "categories"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
<div class="colmask">
|
||||
<div class="section">
|
||||
<div class="padTable"> <a class="main-helplink" href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
|
||||
<div class="padTable">
|
||||
<a class="main-helplink" href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
|
||||
<p>$T('explain-catTags2')<br/>$T('explain-catTags')</p>
|
||||
<hr>
|
||||
<h5 class="darkred"><strong>$T('explain-relFolder'):</strong> <span class="path">$defdir</span></h5>
|
||||
<!--#for $cur, $slot in enumerate($slotinfo)#-->
|
||||
<!--#set $cansort = $slot.name != '*' and $slot.name != ''#-->
|
||||
<form action="save" method="get" <!--#if $cansort#-->class="sorting-row"<!--#end if#-->>
|
||||
<form action="save" method="post" <!--#if $cansort#-->class="sorting-row"<!--#end if#-->>
|
||||
<table class="catTable">
|
||||
<!--#if $cur == 0#-->
|
||||
<tr>
|
||||
@@ -104,29 +105,29 @@
|
||||
</div>
|
||||
<script type="text/javascript" src="${root}staticcfg/js/jquery-ui.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
\$(document).ready(function() {
|
||||
\$('.delCat').click(function() {
|
||||
var theForm = \$(this).closest("form");
|
||||
jQuery(document).ready(function() {
|
||||
jQuery('.delCat').click(function() {
|
||||
var theForm = jQuery(this).closest("form");
|
||||
theForm.attr("action", "delete").submit();
|
||||
});
|
||||
|
||||
// Add autocomplete and file-browser
|
||||
\$('.fileBrowserSmall').typeahead().fileBrowser();
|
||||
jQuery('.fileBrowserSmall').typeahead({appendTo: 'body'}).fileBrowser();
|
||||
|
||||
// Make categories sortable
|
||||
\$('.padTable').sortable({
|
||||
jQuery('.padTable').sortable({
|
||||
items: '.sorting-row',
|
||||
containment: '.colmask',
|
||||
axis: 'y',
|
||||
update: function(event, ui) {
|
||||
\$('.Categories form.sorting-row').each(function(index, elm) {
|
||||
jQuery('.Categories form.sorting-row').each(function(index, elm) {
|
||||
// Update order of all elements
|
||||
if(index != elm.order.value) {
|
||||
if(index !== elm.order.value) {
|
||||
elm.order.value = index
|
||||
// Submit changed order
|
||||
var data = {}
|
||||
\$(elm).extractFormDataTo(data);
|
||||
\$.ajax({
|
||||
jQuery(elm).extractFormDataTo(data);
|
||||
jQuery.ajax({
|
||||
type: "GET",
|
||||
url: window.location.pathname + 'save',
|
||||
data: data,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Folders"#-->
|
||||
<!--#set global $help_uri="configuration/3.0/folders"#-->
|
||||
<!--#set global $help_uri = $confighelpuri + "folders"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<div class="colmask">
|
||||
@@ -10,10 +10,11 @@
|
||||
</div>
|
||||
<form action="saveDirectories" method="post" name="fullform" class="fullform" autocomplete="off">
|
||||
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<input type="hidden" id="ajax" name="ajax" value="1" />
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('userFolders') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3>$T('userFolders') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<p>$T('explain-folderConfig')</p>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
@@ -28,15 +29,26 @@
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="download_free">$T('opt-download_free')</label>
|
||||
<input type="text" name="download_free" id="download_free" value="$download_free" class="smaller_input" />
|
||||
<input type="text" name="download_free" id="download_free" value="$download_free" class="smaller_input" />
|
||||
<span class="desc">$T('explain-download_free')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="complete_dir">$T('opt-complete_dir')</label>
|
||||
<input type="text" name="complete_dir" id="complete_dir" value="$complete_dir" data-initialdir="$my_home" />
|
||||
<span class="desc">$T('explain-complete_dir')</span>
|
||||
<a class="btn btn-default" href="${root}config/sorting/"><span class="glyphicon glyphicon-sort-by-alphabet"></span> $T('cmenu-sorting')</a>
|
||||
<span class="desc">$T('explain-complete_dir') <br/> $T('explain-complete_dir-sorting')</span>
|
||||
</div>
|
||||
<!--#if not $nt#-->
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="complete_free">$T('opt-complete_free')</label>
|
||||
<input type="text" name="complete_free" id="complete_free" value="$complete_free" class="smaller_input" />
|
||||
<span class="desc">$T('explain-download_free') <br>$T('explain-complete_free')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="fulldisk_autoresume">$T('opt-fulldisk_autoresume')</label>
|
||||
<input type="checkbox" name="fulldisk_autoresume" id="fulldisk_autoresume" value="1" <!--#if int($fulldisk_autoresume) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-fulldisk_autoresume')</span>
|
||||
</div>
|
||||
<!--#if not $windows#-->
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="permissions">$T('opt-permissions')</label>
|
||||
<input type="text" name="permissions" id="permissions" value="$permissions" class="smaller_input" />
|
||||
@@ -46,7 +58,7 @@
|
||||
<div class="field-pair">
|
||||
<label class="config" for="dirscan_dir">$T('opt-dirscan_dir')</label>
|
||||
<input type="text" name="dirscan_dir" id="dirscan_dir" value="$dirscan_dir" data-initialdir="$my_home" />
|
||||
<span class="desc">$T('explain-dirscan_dir')</span>
|
||||
<span class="desc">$T('explain-dirscan_dir').replace(".nzb", $file_exts)</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="dirscan_speed">$T('opt-dirscan_speed')</label>
|
||||
@@ -65,7 +77,7 @@
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="password_file">$T('opt-password_file')</label>
|
||||
<input type="text" name="password_file" id="password_file" value="$password_file" />
|
||||
<input type="text" name="password_file" id="password_file" value="$password_file" class="fileBrowserField" data-initialdir="$my_home" data-files="1" />
|
||||
<span class="desc">$T('explain-password_file')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
@@ -79,7 +91,7 @@
|
||||
</div><!-- /section -->
|
||||
<div class="section advanced-settings">
|
||||
<div class="col2">
|
||||
<h3>$T('systemFolders') <a href="$helpuri$help_uri#toc1" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3>$T('systemFolders') <a href="$help_uri#toc1" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<p>$T('explain-folderConfig')</p>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
@@ -93,9 +105,15 @@
|
||||
<span class="desc">$T('explain-admin_dir1')</span>
|
||||
<span class="desc">$T('explain-admin_dir2')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="backup_dir">$T('opt-backup_dir')</label>
|
||||
<input type="text" name="backup_dir" id="backup_dir" value="$backup_dir" data-initialdir="$my_home" />
|
||||
<span class="desc">$T('explain-backup_dir')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="log_dir">$T('opt-log_dir')</label>
|
||||
<input type="text" name="log_dir" id="log_dir" value="$log_dir" data-initialdir="$my_lcldata" />
|
||||
<a class="btn btn-default" id="purge_log_files" href="${root}"><span class="glyphicon glyphicon-trash"></span> $T('purge_log_files')</a>
|
||||
<span class="desc">$T('explain-log_dir')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
@@ -115,7 +133,19 @@
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function() {
|
||||
// Add autocomplete and file-browser
|
||||
\$('.col1 input[name$="_dir"]').typeahead().fileBrowser();
|
||||
jQuery('.col1 input[name$="_dir"], #password_file').typeahead().fileBrowser();
|
||||
|
||||
jQuery('#purge_log_files').click(function () {
|
||||
if ( confirm("$T('confirm')") ) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../../api",
|
||||
data: {mode: 'config', name: 'purge_log_files', output: 'json', apikey: jQuery('#apikey').val()}
|
||||
})
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="General"#-->
|
||||
<!--#set global $help_uri="configuration/3.0/general"#-->
|
||||
<!--#set global $help_uri = $confighelpuri + "general"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<div class="colmask">
|
||||
@@ -9,218 +9,246 @@
|
||||
</label>
|
||||
</div>
|
||||
<form action="saveGeneral" method="post" name="fullform" class="fullform" autocomplete="off">
|
||||
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
|
||||
<input type="hidden" id="ajax" name="ajax" value=1 />
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('webServer') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<p><b>$T('restartRequired')</b></p>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="host">$T('opt-host')</label>
|
||||
<input type="text" name="host" id="host" value="$host" />
|
||||
<span class="desc">$T('explain-host')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="port">$T('opt-port')</label>
|
||||
<input type="number" name="port" id="port" value="$port" size="8" data-original="$port" />
|
||||
<span class="desc">$T('explain-port')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="enable_https">$T('opt-enable_https')</label>
|
||||
<input type="checkbox" name="enable_https" id="enable_https" value="1" <!--#if int($enable_https) > 0 then 'checked="checked" data-original="1"' else ""#-->/>
|
||||
<span class="desc">$T('explain-enable_https')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="web_dir">$T('opt-web_dir')</label>
|
||||
<select name="web_dir" id="web_dir">
|
||||
<!--#for $webline in $web_list#-->
|
||||
<!--#if $webline.lower() == $web_dir.lower()#-->
|
||||
<option value="$webline" selected="selected">$webline</option>
|
||||
<!--#else#-->
|
||||
<option value="$webline">$webline</option>
|
||||
<!--#end if#-->
|
||||
<!--#end for#-->
|
||||
</select>
|
||||
<span class="desc">$T('explain-web_dir') <a href="$caller_url">$caller_url</a></span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="language">$T('opt-language')</label>
|
||||
<select name="language" id="language" class="select">
|
||||
<!--#for $webline in $lang_list#-->
|
||||
<!--#if $webline[0].lower() == $language.lower()#-->
|
||||
<option value="$webline[0]" selected="selected">$webline[1]</option>
|
||||
<!--#else#-->
|
||||
<option value="$webline[0]">$webline[1]</option>
|
||||
<!--#end if#-->
|
||||
<!--#end for#-->
|
||||
</select>
|
||||
<span class="desc">$T('explain-language')</span>
|
||||
<div class="alert alert-info alert-translate">
|
||||
$T('explain-ask-language') <a href="https://sabnzbd.org/wiki/translate" target="_blank" class="alert-link">https://sabnzbd.org/wiki/translate</a>
|
||||
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
|
||||
<input type="hidden" id="ajax" name="ajax" value="1" />
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('webServer') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<p><b>$T('restartRequired')</b></p>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="host">$T('opt-host')</label>
|
||||
<input type="text" name="host" id="host" value="$host" />
|
||||
<span class="desc">$T('explain-host')</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<h5 class="darkred nomargin">$T('base-folder'): <span class="path">$my_lcldata</span></h5>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_port">$T('opt-https_port')</label>
|
||||
<input type="number" name="https_port" id="https_port" value="$https_port" size="8" data-original="$https_port" />
|
||||
<span class="desc">$T('explain-https_port')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_cert">$T('opt-https_cert')</label>
|
||||
<input type="text" name="https_cert" id="https_cert" value="$https_cert" />
|
||||
<button class="btn btn-default generate_cert" title="$T('explain-new-cert')">
|
||||
<span class="glyphicon glyphicon-repeat"></span>
|
||||
</button>
|
||||
<span class="desc">$T('explain-https_cert')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_key">$T('opt-https_key')</label>
|
||||
<input type="text" name="https_key" id="https_key" value="$https_key" />
|
||||
<button class="btn btn-default generate_cert" title="$T('explain-new-cert')">
|
||||
<span class="glyphicon glyphicon-repeat"></span>
|
||||
</button>
|
||||
<span class="desc">$T('explain-https_key')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_chain">$T('opt-https_chain')</label>
|
||||
<input type="text" name="https_chain" id="https_chain" value="$https_chain" />
|
||||
<span class="desc">$T('explain-https_chain')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default sabnzbd_restart"><span class="glyphicon glyphicon-refresh"></span> $T('button-restart') SABnzbd</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('security') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<p><b>$T('restartRequired')</b></p>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<!-- Tricks to avoid browser auto-fill, fixed on-submit with javascript -->
|
||||
<div class="field-pair">
|
||||
<label class="config" for="${pid}_wu">$T('opt-web_username')</label>
|
||||
<input type="text" name="${pid}_wu" id="${pid}_wu" value="$username" data-hide="username" />
|
||||
<span class="desc">$T('explain-web_username')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="${pid}_wp">$T('opt-web_password')</label>
|
||||
<input type="text" name="${pid}_wp" id="${pid}_wp" value="$password" data-hide="password" />
|
||||
<span class="desc">$T('explain-web_password')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="inet_exposure">$T('opt-inet_exposure')</label>
|
||||
<select name="inet_exposure" id="inet_exposure" class="select">
|
||||
<optgroup label="API">
|
||||
<option value="0" <!--#if $inet_exposure == 0 then 'selected="selected"' else ""#-->>$T('inet-local')</option>
|
||||
<option value="1" <!--#if $inet_exposure == 1 then 'selected="selected"' else ""#-->>$T('inet-nzb')</option>
|
||||
<option value="2" <!--#if $inet_exposure == 2 then 'selected="selected"' else ""#-->>$T('inet-api')</option>
|
||||
<option value="3" <!--#if $inet_exposure == 3 then 'selected="selected"' else ""#-->>$T('inet-fullapi')</option>
|
||||
</optgroup>
|
||||
<optgroup label="$T('inet-fullapi') & $T('opt-web_dir')">
|
||||
<option value="4" <!--#if $inet_exposure == 4 then 'selected="selected"' else ""#-->>$T('inet-ui')</option>
|
||||
<option value="5" <!--#if $inet_exposure == 5 then 'selected="selected"' else ""#-->>$T('inet-ui') - $T('inet-external_login')</option>
|
||||
</optgroup>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="port">$T('opt-port')</label>
|
||||
<input type="number" name="port" id="port" value="$port" size="8" data-original="$port" min="0" max="65535" />
|
||||
<span class="desc">$T('explain-port')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="enable_https">$T('opt-enable_https')</label>
|
||||
<input type="checkbox" name="enable_https" id="enable_https" value="1" <!--#if int($enable_https) > 0 then 'checked="checked" data-original="1"' else ""#-->/>
|
||||
<span class="desc">$T('explain-enable_https')</span>
|
||||
<span class="desc"><span class="label label-warning">$T('warning').upper()</span> $T('explain-enable_https_warning')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="web_dir">$T('opt-web_dir')</label>
|
||||
<select name="web_dir" id="web_dir">
|
||||
<!--#for $webline in $web_list#-->
|
||||
<!--#if $webline.lower() == $web_dir.lower()#-->
|
||||
<option value="$webline" selected="selected">$webline</option>
|
||||
<!--#else#-->
|
||||
<option value="$webline">$webline</option>
|
||||
<!--#end if#-->
|
||||
<!--#end for#-->
|
||||
</select>
|
||||
<span class="desc">$T('explain-inet_exposure').replace('. ','.<br><span class="label label-warning">'+$T('warning').upper()+'</span> ')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="local_ranges">$T('opt-local_ranges')</label>
|
||||
<input type="text" name="local_ranges" id="local_ranges" value="$local_ranges" />
|
||||
<span class="desc">$T('explain-local_ranges')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="apikey">$T('opt-apikey')</label>
|
||||
<input type="text" id="apikey" class="fileBrowserField" value="$apikey" readonly />
|
||||
<button class="btn btn-default show_qrcode" title="$T('explain-qr-code')" rel="$apikey" ><span class="glyphicon glyphicon-qrcode"></span></button>
|
||||
<button class="btn btn-default generate_key" id="generate_new_apikey" title="$T('button-apikey')"><span class="glyphicon glyphicon-repeat"></span></button>
|
||||
<span class="desc">$T('explain-apikey')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="nzbkey">$T('opt-nzbkey')</label>
|
||||
<input type="text" id="nzbkey" class="fileBrowserField" value="$nzb_key" readonly />
|
||||
<button class="btn btn-default show_qrcode" title="$T('explain-qr-code')" rel="$nzb_key" ><span class="glyphicon glyphicon-qrcode"></span></button>
|
||||
<button class="btn btn-default generate_key" id="generate_new_nzbkey" title="$T('button-apikey')"><span class="glyphicon glyphicon-repeat"></span></button>
|
||||
<span class="desc">$T('explain-nzbkey')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('cmenu-switches') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="auto_browser">$T('opt-auto_browser')</label>
|
||||
<input type="checkbox" name="auto_browser" id="auto_browser" value="1" <!--#if int($auto_browser) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-auto_browser')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="check_new_rel">$T('opt-check_new_rel')</label>
|
||||
<select name="check_new_rel" id="check_new_rel">
|
||||
<option value="0" <!--#if $check_new_rel == 0 then 'selected="selected"' else ""#--> >$T('off')</option>
|
||||
<option value="1" <!--#if $check_new_rel == 1 then 'selected="selected"' else ""#--> >$T('on')</option>
|
||||
<option value="2" <!--#if $check_new_rel == 2 then 'selected="selected"' else ""#--> >$T('also-test')</option>
|
||||
</select>
|
||||
<span class="desc">$T('explain-check_new_rel')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings <!--#if int($certificate_validation) == 0 then "disabled" else ""#-->">
|
||||
<label class="config" for="enable_https_verification">$T('opt-enable_https_verification')</label>
|
||||
<input type="checkbox" name="enable_https_verification" id="enable_https_verification" value="1" <!--#if int($enable_https_verification) > 0 then 'checked="checked"' else ""#--> <!--#if int($certificate_validation) == 0 then "disabled=\"disabled\"" else ""#--> />
|
||||
<span class="desc">$T('explain-enable_https_verification')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('tuning') <a href="$helpuri$help_uri#toc2" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair value-and-select">
|
||||
<label class="config" for="bandwidth_max_value">$T('opt-bandwidth_max')</label>
|
||||
<input type="number" name="bandwidth_max_value" id="bandwidth_max_value" class="smaller_input" />
|
||||
<select name="bandwidth_max_dropdown" id="bandwidth_max_dropdown">
|
||||
<option value="">B/s</option>
|
||||
<option value="K">KB/s</option>
|
||||
<option value="M" selected>MB/s</option>
|
||||
</select>
|
||||
<input type="hidden" name="bandwidth_max" id="bandwidth_max" value="$bandwidth_max" />
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="bandwidth_perc">$T('opt-bandwidth_perc')</label>
|
||||
<input type="number" name="bandwidth_perc" id="bandwidth_perc" value="$bandwidth_perc" step="10" min="0" max="100"/>
|
||||
<span class="desc">$T('explain-bandwidth_perc')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="cache_limit">$T('opt-cache_limitstr')</label>
|
||||
<input type="text" name="cache_limit" id="cache_limit" value="$cache_limit" class="smaller_input" />
|
||||
<span class="desc">$T('explain-cache_limitstr').replace("64M", "256M").replace("128M", "512M")</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
<span class="desc">$T('explain-web_dir') <a href="$caller_url">$caller_url</a></span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="language">$T('opt-language')</label>
|
||||
<select name="language" id="language" class="select">
|
||||
<!--#for $webline in $lang_list#-->
|
||||
<!--#if $webline[0].lower() == $language.lower()#-->
|
||||
<option value="$webline[0]" selected="selected">$webline[1]</option>
|
||||
<!--#else#-->
|
||||
<option value="$webline[0]">$webline[1]</option>
|
||||
<!--#end if#-->
|
||||
<!--#end for#-->
|
||||
</select>
|
||||
<span class="desc">$T('explain-language')</span>
|
||||
<div class="alert alert-info alert-translate">
|
||||
$T('explain-ask-language') <a href="https://sabnzbd.org/wiki/translate" target="_blank" class="alert-link">https://sabnzbd.org/wiki/translate</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<h5 class="darkred nomargin">$T('base-folder'): <span class="path">$my_lcldata</span></h5>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_port">$T('opt-https_port')</label>
|
||||
<input type="number" name="https_port" id="https_port" value="$https_port" size="8" data-original="$https_port" min="0" max="65535" />
|
||||
<span class="desc">$T('explain-https_port')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_cert">$T('opt-https_cert')</label>
|
||||
<input type="text" name="https_cert" id="https_cert" value="$https_cert" class="fileBrowserField" data-initialdir="$my_lcldata" data-files="1" />
|
||||
<button class="btn btn-default generate_cert" title="$T('explain-new-cert')">
|
||||
<span class="glyphicon glyphicon-repeat"></span>
|
||||
</button>
|
||||
<span class="desc">$T('explain-https_cert')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_key">$T('opt-https_key')</label>
|
||||
<input type="text" name="https_key" id="https_key" value="$https_key" class="fileBrowserField" data-initialdir="$my_lcldata" data-files="1" />
|
||||
<button class="btn btn-default generate_cert" title="$T('explain-new-cert')">
|
||||
<span class="glyphicon glyphicon-repeat"></span>
|
||||
</button>
|
||||
<span class="desc">$T('explain-https_key')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_chain">$T('opt-https_chain')</label>
|
||||
<input type="text" name="https_chain" id="https_chain" value="$https_chain" class="fileBrowserField" data-initialdir="$my_lcldata" data-files="1" />
|
||||
<span class="desc">$T('explain-https_chain')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default sabnzbd_restart"><span class="glyphicon glyphicon-refresh"></span> $T('button-restart') SABnzbd</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('security') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<p><b>$T('restartRequired')</b></p>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<!-- Tricks to avoid browser auto-fill, fixed on-submit with javascript -->
|
||||
<div class="field-pair">
|
||||
<label class="config" for="${pid}_wu">$T('opt-web_username')</label>
|
||||
<input type="text" name="${pid}_wu" id="${pid}_wu" value="$username" data-hide="username" />
|
||||
<span class="desc">$T('explain-web_username')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="${pid}_wp">$T('opt-web_password')</label>
|
||||
<input type="text" name="${pid}_wp" id="${pid}_wp" value="$password" data-hide="password" />
|
||||
<span class="desc">$T('explain-web_password')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="inet_exposure">$T('opt-inet_exposure')</label>
|
||||
<select name="inet_exposure" id="inet_exposure" class="select">
|
||||
<optgroup label="API">
|
||||
<option value="0" <!--#if $inet_exposure == 0 then 'selected="selected"' else ""#-->>$T('inet-local')</option>
|
||||
<option value="1" <!--#if $inet_exposure == 1 then 'selected="selected"' else ""#-->>$T('inet-nzb')</option>
|
||||
<option value="2" <!--#if $inet_exposure == 2 then 'selected="selected"' else ""#-->>$T('inet-api')</option>
|
||||
<option value="3" <!--#if $inet_exposure == 3 then 'selected="selected"' else ""#-->>$T('inet-fullapi')</option>
|
||||
</optgroup>
|
||||
<optgroup label="$T('inet-fullapi') & $T('opt-web_dir')">
|
||||
<option value="4" <!--#if $inet_exposure == 4 then 'selected="selected"' else ""#-->>$T('inet-ui')</option>
|
||||
<option value="5" <!--#if $inet_exposure == 5 then 'selected="selected"' else ""#-->>$T('inet-ui') - $T('inet-external_login')</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<span class="desc">$T('explain-inet_exposure')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="apikey_display">$T('opt-apikey')</label>
|
||||
<input type="text" id="apikey_display" value="$apikey" readonly />
|
||||
<button class="btn btn-default show_qrcode" title="$T('explain-qr-code')" rel="$apikey" ><span class="glyphicon glyphicon-qrcode"></span></button>
|
||||
<button class="btn btn-default generate_key" id="generate_new_apikey" title="$T('button-apikey')"><span class="glyphicon glyphicon-repeat"></span></button>
|
||||
<span class="desc">$T('explain-apikey')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="nzbkey">$T('opt-nzbkey')</label>
|
||||
<input type="text" id="nzbkey" value="$nzb_key" readonly />
|
||||
<button class="btn btn-default show_qrcode" title="$T('explain-qr-code')" rel="$nzb_key" ><span class="glyphicon glyphicon-qrcode"></span></button>
|
||||
<button class="btn btn-default generate_key" id="generate_new_nzbkey" title="$T('button-apikey')"><span class="glyphicon glyphicon-repeat"></span></button>
|
||||
<span class="desc">$T('explain-nzbkey')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('cmenu-switches') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="auto_browser">$T('opt-auto_browser')</label>
|
||||
<input type="checkbox" name="auto_browser" id="auto_browser" value="1" <!--#if int($auto_browser) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-auto_browser')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="check_new_rel">$T('opt-check_new_rel')</label>
|
||||
<select name="check_new_rel" id="check_new_rel">
|
||||
<option value="0" <!--#if $check_new_rel == 0 then 'selected="selected"' else ""#--> >$T('off')</option>
|
||||
<option value="1" <!--#if $check_new_rel == 1 then 'selected="selected"' else ""#--> >$T('on')</option>
|
||||
<option value="2" <!--#if $check_new_rel == 2 then 'selected="selected"' else ""#--> >$T('also-test')</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="enable_https_verification">$T('opt-enable_https_verification')</label>
|
||||
<input type="checkbox" name="enable_https_verification" id="enable_https_verification" value="1" <!--#if int($enable_https_verification) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-enable_https_verification')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="socks5_proxy_url">$T('opt-socks5_proxy_url')</label>
|
||||
<input type="text" name="socks5_proxy_url" id="socks5_proxy_url" value="$socks5_proxy_url" autocomplete="off" placeholder="socks5://user:pass@hostname:port" />
|
||||
<span class="desc">$T('explain-socks5_proxy_url') <br/>$T('readwiki')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('tuning') <a href="$help_uri#toc2" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair value-and-select">
|
||||
<label class="config" for="bandwidth_max_value">$T('opt-bandwidth_max')</label>
|
||||
<input type="number" name="bandwidth_max_value" id="bandwidth_max_value" class="smaller_input" />
|
||||
<select name="bandwidth_max_dropdown" id="bandwidth_max_dropdown">
|
||||
<option value="">B/s</option>
|
||||
<option value="K">KB/s</option>
|
||||
<option value="M" selected>MB/s</option>
|
||||
</select>
|
||||
<input type="hidden" name="bandwidth_max" id="bandwidth_max" value="$bandwidth_max" />
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="bandwidth_perc">$T('opt-bandwidth_perc')</label>
|
||||
<input type="number" name="bandwidth_perc" id="bandwidth_perc" value="$bandwidth_perc" step="10" min="0" max="100"/>
|
||||
<span class="desc">$T('explain-bandwidth_perc')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="cache_limit">$T('opt-cache_limitstr')</label>
|
||||
<input type="text" name="cache_limit" id="cache_limit" value="$cache_limit" class="smaller_input" />
|
||||
<span class="desc">$T('explain-cache_limitstr').replace("64M", "256M").replace("128M", "512M")</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
</form>
|
||||
|
||||
<form action="uploadConfig" method="post" name="fullform" class="fullform" autocomplete="off" enctype="multipart/form-data">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="ajax" value="1" />
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('backup') <a href="$help_uri#toc3" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="create_backup">$T('create-backup')</label>
|
||||
<span class="desc"><button class="btn btn-default createBackup" type="button" id="create_backup"><span class="glyphicon glyphicon glyphicon-import"></span> $T('create-backup')</button></span>
|
||||
<span class="desc">$T('explain-create_backup')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="config_backup_file">$T('restore-backup')</label>
|
||||
<input type="file" accept=".zip" name="config_backup_file" id="config_backup_file" />
|
||||
<span class="desc">$T('restartRequired')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-open"></span> $T('restore-backup')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div><!-- /colmask -->
|
||||
|
||||
@@ -235,98 +263,102 @@
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
\$(document).ready(function(){
|
||||
jQuery(document).ready(function(){
|
||||
// Show the message about translating when it's non-English
|
||||
function hideOrShowTranslate() {
|
||||
if(\$('#language').val() == 'en') {
|
||||
\$('.alert-translate').hide()
|
||||
if(jQuery('#language').val() === 'en') {
|
||||
jQuery('.alert-translate').hide()
|
||||
} else {
|
||||
\$('.alert-translate').show()
|
||||
jQuery('.alert-translate').show()
|
||||
}
|
||||
}
|
||||
\$('#language').on('change', function() {
|
||||
jQuery('#language').on('change', function() {
|
||||
// Show message
|
||||
hideOrShowTranslate()
|
||||
// Re-load page on submit
|
||||
\$('.fullform').submit(function() {
|
||||
jQuery('.fullform').submit(function() {
|
||||
// Skip the fancy stuff, just submit
|
||||
this.submit()
|
||||
})
|
||||
// No JSON reponse
|
||||
\$('#ajax').val('')
|
||||
// No JSON response
|
||||
jQuery('#ajax').val('')
|
||||
})
|
||||
hideOrShowTranslate()
|
||||
|
||||
// Highlight in case user is not safe
|
||||
// So when exposed to internet and no password, no external limit or no username/password
|
||||
var safeCheck = \$('#host, #local_ranges, #inet_exposure, #${pid}_wu, #${pid}_wp')
|
||||
var safeCheck = jQuery('#host, #inet_exposure, #${pid}_wu, #${pid}_wp')
|
||||
function checkSafety() {
|
||||
if(\$('#host').val() != 'localhost' && \$('#host').val() != '127.0.0.1') {
|
||||
if(jQuery('#host').val() !== 'localhost' && jQuery('#host').val() !== '127.0.0.1') {
|
||||
// No limitation on local-network
|
||||
if(!\$('#local_ranges').val() || \$('#inet_exposure').val() > 3) {
|
||||
if(jQuery('#inet_exposure').val() > 3) {
|
||||
// And no username and password?
|
||||
if(!\$('#${pid}_wu').val() || !\$('#${pid}_wp').val()) {
|
||||
if(!jQuery('#${pid}_wu').val() || !jQuery('#${pid}_wp').val()) {
|
||||
// Add warning icon if not there already
|
||||
if(!\$('.host-warning').length) {
|
||||
if(!jQuery('.host-warning').length) {
|
||||
safeCheck.after('<span class="glyphicon glyphicon-alert host-warning"></span>')
|
||||
\$('.host-warning').tooltip({'title': '$T('checkSafety')'})
|
||||
jQuery('.host-warning').tooltip({'title': '$T('checkSafety')'})
|
||||
safeCheck.addClass('host-warning-highlight')
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove warnings
|
||||
\$('.host-warning').remove()
|
||||
jQuery('.host-warning').remove()
|
||||
safeCheck.removeClass('host-warning-highlight')
|
||||
}
|
||||
checkSafety()
|
||||
safeCheck.on('change', checkSafety)
|
||||
|
||||
// Click functions
|
||||
\$('#apikey, #nzbkey').click(function () { \$(this).select() });
|
||||
jQuery('#apikey, #nzbkey').click(function () { jQuery(this).select() });
|
||||
|
||||
\$('#generate_new_apikey').click(function () {
|
||||
if (confirm("$T('Plush-confirm')")) {
|
||||
jQuery('#generate_new_apikey').click(function () {
|
||||
if (confirm("$T('confirm')")) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../../api",
|
||||
data: {mode:'config', name:'set_apikey', apikey: \$('#apikey').val()},
|
||||
data: {mode:'config', name:'set_apikey', apikey: jQuery('#apikey').val()},
|
||||
success: function(msg){
|
||||
\$('#apikey').val(msg);
|
||||
jQuery('#apikey').val(msg);
|
||||
document.location = document.location;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
\$('#generate_new_nzbkey').click(function () {
|
||||
if (confirm("$T('Plush-confirm')")) {
|
||||
jQuery('#generate_new_nzbkey').click(function () {
|
||||
if (confirm("$T('confirm')")) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../../api",
|
||||
data: { mode:'config', name:'set_nzbkey', apikey: \$('#apikey').val() },
|
||||
data: { mode:'config', name:'set_nzbkey', apikey: jQuery('#apikey').val() },
|
||||
success: function(msg){
|
||||
\$('#nzbkey').val(msg);
|
||||
jQuery('#nzbkey').val(msg);
|
||||
document.location = document.location;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
\$('.show_qrcode').click(function (e) {
|
||||
// Add autocomplete and file-browser
|
||||
jQuery('.fileBrowserField').typeahead().fileBrowser();
|
||||
|
||||
jQuery('.show_qrcode').click(function (e) {
|
||||
// Show in modal
|
||||
\$('#modal_qr .modal-dialog').width(330)
|
||||
\$('#modal_qr .modal-body').html('').qrcode({
|
||||
jQuery('#modal_qr .modal-dialog').width(330)
|
||||
jQuery('#modal_qr .modal-body').html('').qrcode({
|
||||
"size": 280,
|
||||
"color": "#3a3",
|
||||
"text": \$(this).attr('rel')
|
||||
"text": jQuery(this).attr('rel')
|
||||
});
|
||||
\$('#modal_qr').modal('show');
|
||||
jQuery('#modal_qr').modal('show');
|
||||
|
||||
// No save on this button click
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
\$('.generate_cert').click(function(e) {
|
||||
jQuery('.generate_cert').click(function(e) {
|
||||
if(!confirm('$T('explain-new-cert')')) {
|
||||
return;
|
||||
}
|
||||
@@ -335,7 +367,7 @@
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../../api",
|
||||
data: { mode: 'config', name: 'regenerate_certs', apikey: \$('#apikey').val() },
|
||||
data: { mode: 'config', name: 'regenerate_certs', apikey: jQuery('#apikey').val() },
|
||||
success: function(msg) {
|
||||
do_restart()
|
||||
}
|
||||
@@ -345,30 +377,44 @@
|
||||
})
|
||||
|
||||
// Only allow re-generate if default certs
|
||||
if(\$('#https_cert').val() != 'server.cert') {
|
||||
\$('.generate_cert').attr('disabled', 'disabled')
|
||||
if(jQuery('#https_cert').val() !== '$def_https_cert_file') {
|
||||
jQuery('.generate_cert').attr('disabled', 'disabled')
|
||||
}
|
||||
|
||||
// Parse the text
|
||||
var bandwidthLimit = \$('#bandwidth_max').val()
|
||||
var bandwidthLimit = jQuery('#bandwidth_max').val()
|
||||
if(bandwidthLimit) {
|
||||
var bandwithLimitNumber = parseFloat(bandwidthLimit)
|
||||
var bandwithLimitText = bandwidthLimit.replace(/[^a-zA-Z]+/g, '');
|
||||
if(bandwithLimitNumber) {
|
||||
\$('#bandwidth_max_value').val(bandwithLimitNumber)
|
||||
\$('#bandwidth_max_dropdown').val(bandwithLimitText)
|
||||
jQuery('#bandwidth_max_value').val(bandwithLimitNumber)
|
||||
jQuery('#bandwidth_max_dropdown').val(bandwithLimitText)
|
||||
}
|
||||
}
|
||||
|
||||
// Update the value
|
||||
\$('#bandwidth_max_value, #bandwidth_max_dropdown').on('change', function() {
|
||||
if(\$('#bandwidth_max_value').val()) {
|
||||
\$('#bandwidth_max').val(\$('#bandwidth_max_value').val() + \$('#bandwidth_max_dropdown').val())
|
||||
jQuery('#bandwidth_max_value, #bandwidth_max_dropdown').on('change', function() {
|
||||
if(jQuery('#bandwidth_max_value').val()) {
|
||||
jQuery('#bandwidth_max').val(jQuery('#bandwidth_max_value').val() + jQuery('#bandwidth_max_dropdown').val())
|
||||
} else {
|
||||
\$('#bandwidth_max').val('')
|
||||
jQuery('#bandwidth_max').val('')
|
||||
}
|
||||
})
|
||||
|
||||
jQuery('#create_backup').click(function () {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../../api",
|
||||
data: {mode:'config', name:'create_backup', output:'json', apikey: jQuery('#apikey').val()},
|
||||
success: function(data) {
|
||||
if(data.value.result) {
|
||||
alert("$T('backup'):\n" + data.value.message)
|
||||
} else {
|
||||
alert("$T('button-failed')")
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,44 +1,49 @@
|
||||
<!--#set global $pane="Email"#-->
|
||||
<!--#set global $help_uri="configuration/3.0/notifications"#-->
|
||||
<!--#set global $help_uri = $confighelpuri + "notifications"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<!--#import apprise#-->
|
||||
|
||||
<!--#def show_notify_checkboxes($section_label)#-->
|
||||
<!--#for $type in $notify_keys#-->
|
||||
<!--#for $type in $notify_types#-->
|
||||
<div class="field-pair">
|
||||
<label class="config wide" for="${section_label}_prio_$type">
|
||||
$T($notify_texts[$type]).replace('/', ' / ') <!--#if $type == 'download'#--> / $T('link-pause') / $T('link-resume')<!--#end if#-->
|
||||
$T($notify_types[$type]).replace('/', ' / ')
|
||||
</label>
|
||||
<input type="checkbox" name="${section_label}_prio_$type" id="${section_label}_prio_$type" value="1" <!--#if int($getVar($section_label + '_prio_' + $type)) > 0 then 'checked="checked"' else ""#--> />
|
||||
<input type="checkbox" name="${section_label}_prio_$type" id="${section_label}_prio_$type" value="1" <!--#if $getVar($section_label + '_prio_' + $type) then 'checked="checked"' else ""#--> />
|
||||
</div>
|
||||
<!--#end for#-->
|
||||
<!--#end def#-->
|
||||
|
||||
<!--#def show_cat_box($section_label)#-->
|
||||
<div class="col2-cats" <!--#if int($getVar($section_label + '_enable')) > 0 then '' else 'style="display:none"'#-->>
|
||||
<div class="col2-cats" <!--#if $getVar($section_label + '_enable') then '' else 'style="display:none"'#-->>
|
||||
<hr>
|
||||
<b>$T('affectedCat')</b><br/>
|
||||
<select name="${section_label}_cats" multiple="multiple" class="multiple_cats">
|
||||
<select name="${section_label}_cats" multiple="multiple" class="multiple_cats" size="$len($categories)">
|
||||
<!--#for $ct in $categories#-->
|
||||
<option value="$ct" <!--#if $ct in $getVar($section_label + '_cats') then 'selected="selected"' else ""#-->>$Tspec($ct)</option>
|
||||
<!--#end for#-->
|
||||
</select>
|
||||
<p>$T('defaultNotifiesAll')</p>
|
||||
</div>
|
||||
<!--#end def#-->
|
||||
|
||||
<div class="colmask">
|
||||
<form action="saveEmail" method="post" name="fullform" class="fullform" autocomplete="off">
|
||||
<form action="saveNotify" method="post" name="fullform" class="fullform" autocomplete="off">
|
||||
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<input type="hidden" id="ajax" name="ajax" value="1" />
|
||||
<div class="section" id="email">
|
||||
<div class="col2">
|
||||
<h3>$T('cmenu-email') <a href="$helpuri$help_uri#toc0" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3>$T('cmenu-email') <a href="$help_uri#toc0" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<div class="col2-cats" <!--#if int($email_endjob) > 0 then '' else 'style="display:none"'#-->>
|
||||
<b>$T('affectedCat')</b><br/>
|
||||
<select name="email_cats" multiple="multiple" class="multiple_cats">
|
||||
<select name="email_cats" multiple="multiple" class="multiple_cats" size="$len($categories)">
|
||||
<!--#for $ct in $categories#-->
|
||||
<option value="$ct" <!--#if $ct in $email_cats then 'selected="selected"' else ""#-->>$Tspec($ct)</option>
|
||||
<!--#end for#-->
|
||||
</select>
|
||||
<p>$T('defaultNotifiesAll')</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col1">
|
||||
@@ -53,12 +58,12 @@
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="email_full">$T('opt-email_full')</label>
|
||||
<input type="checkbox" name="email_full" id="email_full" value="1" <!--#if int($email_full) > 0 then 'checked="checked"' else ""#--> />
|
||||
<input type="checkbox" name="email_full" id="email_full" value="1" <!--#if $email_full then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-email_full')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="email_rss">$T('opt-email_rss')</label>
|
||||
<input type="checkbox" name="email_rss" id="email_rss" value="1" <!--#if int($email_rss) > 0 then 'checked="checked"' else ""#--> />
|
||||
<input type="checkbox" name="email_rss" id="email_rss" value="1" <!--#if $email_rss then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-email_rss')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
@@ -102,12 +107,12 @@
|
||||
<h3>$T('section-NC')</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="ncenter_enable" id="ncenter_enable" value="1" <!--#if int($ncenter_enable) > 0 then 'checked="checked"' else ""#--> /></td>
|
||||
<td><input type="checkbox" name="ncenter_enable" id="ncenter_enable" value="1" <!--#if $ncenter_enable then 'checked="checked"' else ""#--> /></td>
|
||||
<td><label for="ncenter_enable"> $T('opt-ncenter_enable')</label></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col1" <!--#if int($ncenter_enable) > 0 then '' else 'style="display:none"'#-->>
|
||||
<div class="col1" <!--#if $ncenter_enable then '' else 'style="display:none"'#-->>
|
||||
<fieldset>
|
||||
$show_notify_checkboxes('ncenter')
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
@@ -121,19 +126,19 @@
|
||||
</div>
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
<!--#if $nt#-->
|
||||
<!--#if $windows#-->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('section-AC')</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="acenter_enable" id="acenter_enable" value="1" <!--#if int($acenter_enable) > 0 then 'checked="checked"' else ""#--> /></td>
|
||||
<td><input type="checkbox" name="acenter_enable" id="acenter_enable" value="1" <!--#if $acenter_enable then 'checked="checked"' else ""#--> /></td>
|
||||
<td><label for="acenter_enable"> $T('opt-acenter_enable')</label></td>
|
||||
</tr>
|
||||
</table>
|
||||
$show_cat_box('acenter')
|
||||
</div>
|
||||
<div class="col1" <!--#if int($acenter_enable) > 0 then '' else 'style="display:none"'#-->>
|
||||
<div class="col1" <!--#if $acenter_enable then '' else 'style="display:none"'#-->>
|
||||
<fieldset>
|
||||
$show_notify_checkboxes('acenter')
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
@@ -150,16 +155,16 @@
|
||||
<!--#if $have_ntfosd#-->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('section-OSD') <a href="$helpuri$help_uri#toc4" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3>$T('section-OSD') <a href="$help_uri#toc4" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="ntfosd_enable" id="ntfosd_enable" value="1" <!--#if int($ntfosd_enable) > 0 then 'checked="checked"' else ""#--> /></td>
|
||||
<td><input type="checkbox" name="ntfosd_enable" id="ntfosd_enable" value="1" <!--#if $ntfosd_enable then 'checked="checked"' else ""#--> /></td>
|
||||
<td><label for="ntfosd_enable"> $T('opt-ntfosd_enable')</label></td>
|
||||
</tr>
|
||||
</table>
|
||||
$show_cat_box('ntfosd')
|
||||
</div>
|
||||
<div class="col1" <!--#if int($ntfosd_enable) > 0 then '' else 'style="display:none"'#-->>
|
||||
<div class="col1" <!--#if $ntfosd_enable then '' else 'style="display:none"'#-->>
|
||||
<fieldset>
|
||||
$show_notify_checkboxes('ntfosd')
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
@@ -173,19 +178,64 @@
|
||||
</div>
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
<div class="section" id="nscript">
|
||||
<div class="section" id="apprise">
|
||||
<div class="col2">
|
||||
<h3>$T('section-NScript')</h3>
|
||||
<h3>Apprise <a href="$help_uri#apprise" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="nscript_enable" id="nscript_enable" value="1" <!--#if int($nscript_enable) > 0 then 'checked="checked"' else ""#--> /></td>
|
||||
<td><input type="checkbox" name="apprise_enable" id="apprise_enable" value="1" <!--#if $apprise_enable then 'checked="checked"' else ""#--> /></td>
|
||||
<td><label for="apprise_enable"> $T('opt-apprise_enable')</label></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>$T('explain-apprise_enable')</p>
|
||||
<p>$T('version'): ${apprise.__version__}</p>
|
||||
|
||||
$show_cat_box('apprise')
|
||||
</div>
|
||||
<div class="col1" <!--#if $apprise_enable then '' else 'style="display:none"'#-->>
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="apprise_urls">$T('opt-apprise_urls')</label>
|
||||
<input type="text" name="apprise_urls" id="apprise_urls" value="$apprise_urls" />
|
||||
<span class="desc">$T('explain-apprise_urls')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<span class="desc">$T('explain-apprise_extra_urls')</span>
|
||||
</div>
|
||||
<!--#set $section_label = 'apprise'#-->
|
||||
<!--#for $type in $notify_types#-->
|
||||
<div class="field-pair">
|
||||
<label class="config" for="${section_label}_target_${type}">
|
||||
$T($notify_types[$type]).replace('/', ' / ')
|
||||
</label>
|
||||
<input type="checkbox" name="${section_label}_target_${type}_enable" id="${section_label}_target_${type}_enable" value="1" <!--#if $getVar($section_label + '_target_' + $type + '_enable') then 'checked="checked"' else ""#--> />
|
||||
<input type="text" name="${section_label}_target_${type}" id="${section_label}_target_${type}" value="$getVar($section_label + '_target_' + $type)" placeholder="$T('opt-apprise_urls')" />
|
||||
</div>
|
||||
<!--#end for#-->
|
||||
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default" type="button" id="test_apprise"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
|
||||
</div>
|
||||
<div class="field-pair result-box">
|
||||
<div class="alert"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="nscript">
|
||||
<div class="col2">
|
||||
<h3>$T('section-NScript') <a href="$help_uri#nscript" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="nscript_enable" id="nscript_enable" value="1" <!--#if $nscript_enable then 'checked="checked"' else ""#--> /></td>
|
||||
<td><label for="nscript_enable"> $T('opt-nscript_enable')</label></td>
|
||||
</tr>
|
||||
</table>
|
||||
<em>$T('explain-nscript_enable')</em><br><a href="$helpuri$help_uri#nscript" target="_blank">$T('readwiki')</a>
|
||||
<em>$T('explain-nscript_enable')</em><br><a href="$help_uri#nscript" target="_blank">$T('readwiki')</a>
|
||||
$show_cat_box('nscript')
|
||||
</div>
|
||||
<div class="col1" <!--#if int($nscript_enable) > 0 then '' else 'style="display:none"'#-->>
|
||||
<div class="col1" <!--#if $nscript_enable then '' else 'style="display:none"'#-->>
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="nscript_script">$T('opt-nscript_script')</label>
|
||||
@@ -199,7 +249,7 @@
|
||||
<div class="field-pair">
|
||||
<label class="config" for="nscript_parameters">$T('opt-nscript_parameters')</label>
|
||||
<input type="text" name="nscript_parameters" id="nscript_parameters" value="$nscript_parameters" />
|
||||
<span class="desc">$T('Optional') - $T('explain-nscript_parameters')</span>
|
||||
<span class="desc">$T('Optional') - $T('readwiki')</span>
|
||||
</div>
|
||||
$show_notify_checkboxes('nscript')
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
@@ -217,14 +267,14 @@
|
||||
<h3>$T('section-Prowl')</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="prowl_enable" id="prowl_enable" value="1" <!--#if int($prowl_enable) > 0 then 'checked="checked"' else ""#--> /></td>
|
||||
<td><input type="checkbox" name="prowl_enable" id="prowl_enable" value="1" <!--#if $prowl_enable then 'checked="checked"' else ""#--> /></td>
|
||||
<td><label for="prowl_enable"> $T('opt-prowl_enable')</label></td>
|
||||
</tr>
|
||||
</table>
|
||||
<em>$T('explain-prowl_enable')</em>
|
||||
$show_cat_box('prowl')
|
||||
</div>
|
||||
<div class="col1" <!--#if int($prowl_enable) > 0 then '' else 'style="display:none"'#-->>
|
||||
<div class="col1" <!--#if $prowl_enable then '' else 'style="display:none"'#-->>
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="prowl_apikey">$T('opt-prowl_apikey')</label>
|
||||
@@ -232,10 +282,10 @@
|
||||
<span class="desc">$T('explain-prowl_apikey')</span>
|
||||
</div>
|
||||
<!--#set $section_label = 'prowl'#-->
|
||||
<!--#for $type in $notify_keys#-->
|
||||
<!--#for $type in $notify_types#-->
|
||||
<div class="field-pair">
|
||||
<label class="config" for="${section_label}_prio_$type">
|
||||
$T($notify_texts[$type]).replace('/', ' / ') <!--#if $type == 'download'#--> / $T('link-pause') / $T('link-resume')<!--#end if#-->
|
||||
$T($notify_types[$type]).replace('/', ' / ')
|
||||
</label>
|
||||
<select name="${section_label}_prio_$type" id="${section_label}_prio_$type">
|
||||
<option value="-3" <!--#if $getVar($section_label + '_prio_' + $type) == -3 then 'selected="selected"' else ""#--> >$T('prowl-off')</option>
|
||||
@@ -263,14 +313,14 @@
|
||||
<h3>$T('section-Pushover')</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="pushover_enable" id="pushover_enable" value="1" <!--#if int($pushover_enable) > 0 then 'checked="checked"' else ""#--> /></td>
|
||||
<td><input type="checkbox" name="pushover_enable" id="pushover_enable" value="1" <!--#if $pushover_enable then 'checked="checked"' else ""#--> /></td>
|
||||
<td><label for="pushover_enable"> $T('opt-pushover_enable')</label></td>
|
||||
</tr>
|
||||
</table>
|
||||
<em>$T('explain-pushover_enable')</em>
|
||||
$show_cat_box('pushover')
|
||||
</div>
|
||||
<div class="col1" <!--#if int($pushover_enable) > 0 then '' else 'style="display:none"'#-->>
|
||||
<div class="col1" <!--#if $pushover_enable then '' else 'style="display:none"'#-->>
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="pushover_token">$T('opt-pushover_token')</label>
|
||||
@@ -298,10 +348,10 @@
|
||||
<span class="desc">$T('explain-pushover_emergency_expire')</span>
|
||||
</div>
|
||||
<!--#set $section_label = 'pushover'#-->
|
||||
<!--#for $type in $notify_keys#-->
|
||||
<!--#for $type in $notify_types#-->
|
||||
<div class="field-pair">
|
||||
<label class="config" for="${section_label}_prio_$type">
|
||||
$T($notify_texts[$type]).replace('/', ' / ') <!--#if $type == 'download'#--> / $T('link-pause') / $T('link-resume')<!--#end if#-->
|
||||
$T($notify_types[$type]).replace('/', ' / ')
|
||||
</label>
|
||||
<select name="${section_label}_prio_$type" id="${section_label}_prio_$type">
|
||||
<option value="-3" <!--#if $getVar($section_label + '_prio_' + $type) == -3 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
|
||||
@@ -328,14 +378,14 @@
|
||||
<h3>$T('section-Pushbullet')</h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="pushbullet_enable" id="pushbullet_enable" value="1" <!--#if int($pushbullet_enable) > 0 then 'checked="checked"' else ""#--> /></td>
|
||||
<td><input type="checkbox" name="pushbullet_enable" id="pushbullet_enable" value="1" <!--#if $pushbullet_enable then 'checked="checked"' else ""#--> /></td>
|
||||
<td><label for="pushbullet_enable"> $T('opt-pushbullet_enable')</label></td>
|
||||
</tr>
|
||||
</table>
|
||||
<em>$T('explain-pushbullet_enable')</em>
|
||||
$show_cat_box('pushbullet')
|
||||
</div>
|
||||
<div class="col1" <!--#if int($pushbullet_enable) > 0 then '' else 'style="display:none"'#-->>
|
||||
<div class="col1" <!--#if $pushbullet_enable then '' else 'style="display:none"'#-->>
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="pushbullet_apikey">$T('opt-pushbullet_apikey')</label>
|
||||
@@ -364,24 +414,24 @@
|
||||
</div><!-- /colmask -->
|
||||
|
||||
<script type="text/javascript">
|
||||
\$(document).ready(function(){
|
||||
jQuery(document).ready(function(){
|
||||
// Expand on enable
|
||||
\$('.col2 input[name$="enable"]').change(function() {
|
||||
jQuery('.col2 input[name$="enable"]').change(function() {
|
||||
if(this.checked) {
|
||||
\$(this).parents('.section').find('.col1').show()
|
||||
\$(this).parents('.col2').find('.col2-cats').show()
|
||||
jQuery(this).parents('.section').find('.col1').show()
|
||||
jQuery(this).parents('.col2').find('.col2-cats').show()
|
||||
} else {
|
||||
\$(this).parents('.section').find('.col1').hide()
|
||||
\$(this).parents('.col2').find('.col2-cats').hide()
|
||||
jQuery(this).parents('.section').find('.col1').hide()
|
||||
jQuery(this).parents('.col2').find('.col2-cats').hide()
|
||||
}
|
||||
\$('form').submit()
|
||||
jQuery('form').submit()
|
||||
addRowColor()
|
||||
})
|
||||
\$('#email_endjob').change(function() {
|
||||
if(\$(this).val() > 0) {
|
||||
\$(this).parents('.section').find('.col2-cats').show()
|
||||
jQuery('#email_endjob').change(function() {
|
||||
if(jQuery(this).val() > 0) {
|
||||
jQuery(this).parents('.section').find('.col2-cats').show()
|
||||
} else {
|
||||
\$(this).parents('.section').find('.col2-cats').hide()
|
||||
jQuery(this).parents('.section').find('.col2-cats').hide()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -390,27 +440,27 @@
|
||||
**/
|
||||
function testNotification(buttonObj) {
|
||||
// Confirm?
|
||||
if(\$(buttonObj).attr('rel')) {
|
||||
if(!confirm(\$(buttonObj).attr('rel'))) return false;
|
||||
if(jQuery(buttonObj).attr('rel')) {
|
||||
if(!confirm(jQuery(buttonObj).attr('rel'))) return false;
|
||||
}
|
||||
// Disable button and get the data
|
||||
\$(buttonObj).attr("disabled", "disabled")
|
||||
\$(buttonObj).find('span').toggleClass('glyphicon-comment glyphicon-refresh spin-glyphicon')
|
||||
jQuery(buttonObj).attr("disabled", "disabled")
|
||||
jQuery(buttonObj).find('span').toggleClass('glyphicon-comment glyphicon-refresh spin-glyphicon')
|
||||
var data = { mode: buttonObj.id, apikey: '$apikey', output: 'json' };
|
||||
\$(buttonObj).parents('.section').extractFormDataTo(data);
|
||||
jQuery(buttonObj).parents('.section').extractFormDataTo(data);
|
||||
|
||||
// Clear up the box
|
||||
resultBox = \$(buttonObj).parents('.section').find('.result-box .alert');
|
||||
resultBox = jQuery(buttonObj).parents('.section').find('.result-box .alert');
|
||||
|
||||
// Get the request
|
||||
\$.ajax({
|
||||
jQuery.ajax({
|
||||
type: "GET",
|
||||
url: "../../api",
|
||||
data: data
|
||||
}).then(function(data) {
|
||||
// Remove disabled and make the box
|
||||
\$(buttonObj).removeAttr("disabled")
|
||||
\$(buttonObj).find('span').toggleClass('glyphicon-comment glyphicon-refresh spin-glyphicon')
|
||||
jQuery(buttonObj).removeAttr("disabled")
|
||||
jQuery(buttonObj).find('span').toggleClass('glyphicon-comment glyphicon-refresh spin-glyphicon')
|
||||
resultBox.removeClass('alert-success alert-danger').show()
|
||||
if(data.status) {
|
||||
resultBox.addClass('alert-success')
|
||||
@@ -423,7 +473,7 @@
|
||||
}
|
||||
})
|
||||
}
|
||||
\$('#test_email, #test_notif, #test_windows, #test_pushbullet, #test_pushover, #test_prowl, #test_osd, #test_nscript').click(function () {
|
||||
jQuery('#test_email, #test_notif, #test_windows, #test_apprise, #test_pushbullet, #test_pushover, #test_prowl, #test_osd, #test_nscript').click(function () {
|
||||
testNotification(this)
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1,29 +1,30 @@
|
||||
<!--#set global $pane="RSS"#-->
|
||||
<!--#set global $help_uri="configuration/3.0/rss"#-->
|
||||
<!--#set global $help_uri = $confighelpuri + "rss"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
<!--#import html#-->
|
||||
<div class="colmask">
|
||||
<!--#if not $active_feed#-->
|
||||
<div class="section">
|
||||
<div class="padTable">
|
||||
<a class="main-helplink" href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
|
||||
<a class="main-helplink" href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
|
||||
<p>$T('explain-RSS')</p>
|
||||
<form action="add_rss_feed" method="post" autocomplete="off">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<table class="catTable">
|
||||
<table class="catTable addRssTable">
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>$T('name')</th>
|
||||
<th>$T('feed') URL</th>
|
||||
<th>$T('feed') URLs</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>
|
||||
<input type="checkbox" name="enable" value="1" checked />
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="feed" class="smaller_input" value="$feed" />
|
||||
<td class="new-feed-title">
|
||||
<input type="text" name="feed" value="$feed" />
|
||||
</td>
|
||||
<td>
|
||||
<td class="new-feed-url">
|
||||
<input type="text" name="uri" placeholder="$T('addMultipleFeeds')" />
|
||||
</td>
|
||||
<td class="nowrap">
|
||||
@@ -45,20 +46,21 @@
|
||||
<!--#set $odd = False#-->
|
||||
<!--#for $feed_item in $feeds#-->
|
||||
<!--#set $odd = not $odd#-->
|
||||
<!--#set $feed_item_html = html.escape($feed_item)#-->
|
||||
<tr class="data-row <!--#if $odd then " alt " else " "#-->">
|
||||
<td class="chk">
|
||||
<input type="checkbox" class="toggleFeedCheckbox" name="enable" value="1" <!--#if int($rss[$feed_item]['enable']) !=0 then 'checked="checked"' else ""#--> rel="$feed_item" />
|
||||
<input type="checkbox" class="toggleFeedCheckbox" name="enable" value="1" <!--#if int($rss[$feed_item]['enable']) !=0 then 'checked="checked"' else ""#--> rel="$feed_item_html" />
|
||||
</td>
|
||||
<td class="title">
|
||||
<a href="?feed=$rss[$feed_item]['link']" class="subscription-title path feed <!--#if int($rss[$feed_item]['enable']) != 0 then 'feed_enabled' else 'feed_disabled'#-->">
|
||||
$feed_item
|
||||
$feed_item_html
|
||||
</a>
|
||||
</td>
|
||||
<td class="controls">
|
||||
<button type="button" class="btn btn-default testFeed" rel="$feed_item"><span class="glyphicon glyphicon-sort"></span> $T('button-preFeed')</button>
|
||||
<button type="button" class="btn btn-default testFeed" rel="$feed_item_html"><span class="glyphicon glyphicon-sort"></span> $T('button-preFeed')</button>
|
||||
<input type="hidden" name="uri" value="$rss[$feed_item]['uris']" />
|
||||
<button type="button" class="btn btn-default editFeed" rel="$feed_item"><span class="glyphicon glyphicon-pencil"></span> $T('Edit')</button>
|
||||
<button type="button" class="btn btn-default delFeed" rel="$feed_item"><span class="glyphicon glyphicon-trash"></span></button>
|
||||
<button type="button" class="btn btn-default editFeed" rel="$feed_item_html"><span class="glyphicon glyphicon-pencil"></span> $T('rss-edit')</button>
|
||||
<button type="button" class="btn btn-default delFeed" rel="$feed_item_html"><span class="glyphicon glyphicon-trash"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
<!--#for $uri_index, $uri in enumerate($rss[$feed_item]['uri'])#-->
|
||||
@@ -90,7 +92,7 @@
|
||||
<label class="config narrow" for="rss_rate">$T('opt-rss_rate')</label>
|
||||
<input type="number" name="rss_rate" id="rss_rate" value="$rss_rate" min="15" max="1440" />
|
||||
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-ok"></span> $T('button-save')</button>
|
||||
<span class="config narrow"> $T('Next scan at:') $rss_next</span>
|
||||
<span class="config narrow"> $T('rss-nextscan'): $rss_next</span>
|
||||
<span class="desc narrow">$T('explain-rss_rate')</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
@@ -100,13 +102,13 @@
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
<!--#if $active_feed#-->
|
||||
<!--#set $feed = $active_feed#-->
|
||||
<!--#set $feed = html.unescape($active_feed)#-->
|
||||
<div class="section rss-section">
|
||||
<div class="padTable">
|
||||
<a class="main-helplink" href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
|
||||
<a class="main-helplink" href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
|
||||
<h2 class="nomargin activeRSS">
|
||||
<a href="${root}config/rss/">$T('cmenu-rss')</a> »
|
||||
<a href="$rss[$active_feed]['uri']" onclick="window.open(this.href); return false;">$active_feed</a>
|
||||
$active_feed
|
||||
</h2>
|
||||
<!--#if $error#-->
|
||||
<div class="alert alert-danger">
|
||||
@@ -116,7 +118,7 @@
|
||||
<!--#end if#-->
|
||||
<form action="upd_rss_feed" method="post">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="feed" value="$feed" />
|
||||
<input type="hidden" name="feed" value="$active_feed" />
|
||||
<input type="hidden" name="uri" value="$rss[$feed]['uris']" />
|
||||
<table class="catTable">
|
||||
<thead>
|
||||
@@ -208,7 +210,7 @@
|
||||
<form action="upd_rss_filter" method="post">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="index" value="$rss[$feed]['filtercount']" />
|
||||
<input type="hidden" name="feed" value="$feed" />
|
||||
<input type="hidden" name="feed" value="$active_feed" />
|
||||
<table class="catTable">
|
||||
<tbody>
|
||||
<tr>
|
||||
@@ -284,7 +286,7 @@
|
||||
<form action="upd_rss_filter" method="post" autocomplete="off">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="index" value="$fnum" />
|
||||
<input type="hidden" name="feed" value="$feed" />
|
||||
<input type="hidden" name="feed" value="$active_feed" />
|
||||
<table class="catTable">
|
||||
<tbody>
|
||||
<tr class="<!--#if $odd then " alt " else " "#--> <!--#if $filter[3]!="A" and $filter[3]!="S" then 'disabled_options_rule' else ""#-->">
|
||||
@@ -300,8 +302,8 @@
|
||||
<option value="M" <!--#if $filter[3]=="M" then 'selected="selected"' else ""#-->> $T('rss-must')</option>
|
||||
<option value="R" <!--#if $filter[3]=="R" then 'selected="selected"' else ""#-->> $T('rss-reject')</option>
|
||||
<option value="C" <!--#if $filter[3]=="C" then 'selected="selected"' else ""#-->> $T('rss-mustcat')</option>
|
||||
<option value=">" <!--#if $filter[3]==">" then 'selected="selected"' else ""#-->> $T('rss-atleast')</option>
|
||||
<option value="<" <!--#if $filter[3]=="<" then 'selected="selected"' else ""#-->> $T('rss-atmost')</option>
|
||||
<option value=">" <!--#if $filter[3]==">" then 'selected="selected"' else ""#-->> $T('rss-atleast')</option>
|
||||
<option value="<" <!--#if $filter[3]=="<" then 'selected="selected"' else ""#-->> $T('rss-atmost')</option>
|
||||
<option value="F" <!--#if $filter[3]=="F" then 'selected="selected"' else ""#-->> $T('rss-from')</option>
|
||||
<option value="S" <!--#if $filter[3]=="S" then 'selected="selected"' else ""#-->> $T('rss-from-show') ($T('rss-accept'))</option>
|
||||
</select>
|
||||
@@ -361,13 +363,13 @@
|
||||
<!--#end for#-->
|
||||
<form action="download_rss_feed" method="post">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="feed" value="$feed" />
|
||||
<input type="hidden" name="feed" value="$active_feed" />
|
||||
<div class="padding">
|
||||
<button type="button" class="btn btn-default testFeed" rel="$feed"><span class="glyphicon glyphicon-sort"></span> $T('button-preFeed')</button>
|
||||
<button type="button" class="btn btn-default testFeed" rel="$active_feed"><span class="glyphicon glyphicon-sort"></span> $T('button-preFeed')</button>
|
||||
<button type="submit" class="btn btn-default Save"><span class="glyphicon glyphicon-forward"></span> $T('button-forceFeed')</button>
|
||||
<button type="button" class="btn btn-default cleanFeed"><span class="glyphicon glyphicon-trash"></span> $T('button-clear') $T('rss-done')</button>
|
||||
<!--#if $evalButton#-->
|
||||
<button type="button" class="btn btn-default evalFeed" rel="$feed"><span class="glyphicon glyphicon-ok-circle"></span> $T('button-evalFeed')</button>
|
||||
<button type="button" class="btn btn-default evalFeed" rel="$active_feed"><span class="glyphicon glyphicon-ok-circle"></span> $T('button-evalFeed')</button>
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
</form>
|
||||
@@ -400,7 +402,7 @@
|
||||
<tr class="infoTableSeperator">
|
||||
<td>
|
||||
<form action="download" method="get">
|
||||
<input type="hidden" value="$feed" name="feed" />
|
||||
<input type="hidden" value="$active_feed" name="feed" />
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="url" value="$job['url']" />
|
||||
<input type="hidden" name="nzbname" value="$job['nzbname']" />
|
||||
@@ -444,7 +446,7 @@
|
||||
<tr class="infoTableSeperator">
|
||||
<td>
|
||||
<form action="download" method="get">
|
||||
<input type="hidden" value="$feed" name="feed" />
|
||||
<input type="hidden" value="$active_feed" name="feed" />
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="url" value="$job['url']" />
|
||||
<input type="hidden" name="nzbname" value="$job['nzbname']" />
|
||||
@@ -473,24 +475,28 @@
|
||||
<div class="tab-pane padTable" id="rss-tab-done">
|
||||
<!--#if $downloaded#-->
|
||||
<form action="clean_rss_jobs" method="post">
|
||||
<input type="hidden" value="$feed" name="feed" />
|
||||
<input type="hidden" value="$active_feed" name="feed" />
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<table class="catTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="default-sort">$T('rss-added')</th>
|
||||
<th>$T('rss-filter')</th>
|
||||
<th>$T('size')</th>
|
||||
<th width="60%">$T('sort-title')</th>
|
||||
<th>$T('category')</th>
|
||||
<th>$T('nzo-age')</th>
|
||||
<th>$T('source')</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!--#for $job in $downloaded#-->
|
||||
<tr class="infoTableSeperator">
|
||||
<td data-sort-value="$job['time_downloaded_ms']">$job['time_downloaded']</td>
|
||||
<td>$job['rule'] $job['skip']</td>
|
||||
<td data-sort-value="$job['size']">$job['size_units']</td>
|
||||
<td>$job['title']</td>
|
||||
<td>$job['cat']</td>
|
||||
<td data-sort-value="$job['age_ms']">$job['age']</td>
|
||||
<td data-sort-value="$job['baselink']" title="$job['baselink']">
|
||||
<!--#if not $job['infourl']#-->
|
||||
<div class="favicon source-icon" style="background-image: url(//$job['baselink']/favicon.ico);" data-domain="$job['baselink']"></div>
|
||||
@@ -508,56 +514,80 @@
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- /colmask -->
|
||||
|
||||
<form method="post" action="save_rss_feed" class="modal fade" id="rss_edit_modal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">$T('Edit') <span id="feed_edit_name_label"></span></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="feed_edit_new_name">$T('name')</label>
|
||||
<input type="text" class="form-control" name="feed_new_name" id="feed_edit_new_name" placeholder="$T('name')" size="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="feed_edit_url">$T('feed') URLs</label>
|
||||
<input type="text" class="form-control" name="uri" id="feed_edit_url" placeholder="$T('feed') URLs" size="">
|
||||
<span class="help-block">$T('addMultipleFeeds')</span>
|
||||
</div>
|
||||
<input type="hidden" name="feed" id="feed_edit_old_name" />
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-danger" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> $T('cancel')</button>
|
||||
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-ok"></span> $T('rss-accept')</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</form><!-- /.modal -->
|
||||
|
||||
<script type="text/javascript" src="${root}staticcfg/js/jquery.tablesort.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
function urlencode(str) {
|
||||
return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
|
||||
}
|
||||
|
||||
\$(document).ready(function(){
|
||||
\$('.favicon').each(function(i, theContainer) {
|
||||
jQuery(document).ready(function(){
|
||||
jQuery('.favicon').each(function(i, theContainer) {
|
||||
// Easy favicon grabber
|
||||
var favUrl = '//' + \$(theContainer).data('domain') + '/favicon.ico'
|
||||
var favUrl = '//' + jQuery(theContainer).data('domain') + '/favicon.ico'
|
||||
|
||||
// Does the image exist? Otherwise place a glyphicon
|
||||
var testFavImg = new Image();
|
||||
testFavImg.src = favUrl;
|
||||
testFavImg.onerror = function (evt){
|
||||
\$(theContainer).append('<span class="glyphicon glyphicon-list"></span>')
|
||||
jQuery(theContainer).append('<span class="glyphicon glyphicon-list"></span>')
|
||||
}
|
||||
})
|
||||
|
||||
\$('.tabs a').click(function (e) {
|
||||
jQuery('.tabs a').click(function (e) {
|
||||
e.preventDefault()
|
||||
\$(this).tab('show')
|
||||
jQuery(this).tab('show')
|
||||
})
|
||||
|
||||
\$('.editFeed').click(function(){
|
||||
var oldURI = \$(this).prev().val();
|
||||
var newURI = prompt("$T('feed') URL. \n$T('addMultipleFeeds').", oldURI );
|
||||
if(newURI != "" && newURI !== null) {
|
||||
var whichFeed = \$(this).attr("rel");
|
||||
var isEnabled = \$('.toggleFeedCheckbox[rel="'+whichFeed+'"]').attr('checked') == "checked"? 1 : 0;
|
||||
\$.ajax({
|
||||
type: "POST",
|
||||
url: "save_rss_feed",
|
||||
data: {feed: whichFeed, uri: newURI, enable: isEnabled, apikey: "$apikey" }
|
||||
}).done(function( msg ) {
|
||||
location.reload();
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
jQuery('.editFeed').click(function(){
|
||||
var oldURI = jQuery(this).prev().val();
|
||||
var whichFeed = jQuery(this).attr("rel");
|
||||
|
||||
// Fill the values
|
||||
jQuery('#feed_edit_name_label').text(whichFeed)
|
||||
jQuery('#feed_edit_old_name').val(whichFeed)
|
||||
jQuery('#feed_edit_new_name').val(whichFeed)
|
||||
jQuery('#feed_edit_url').val(oldURI)
|
||||
|
||||
// Show the modal
|
||||
jQuery('#rss_edit_modal').modal('show');
|
||||
});
|
||||
|
||||
\$('.delFeed').click(function(e){
|
||||
jQuery('.delFeed').click(function(e){
|
||||
e.preventDefault();
|
||||
if ( confirm("$T('confirm')") ) {
|
||||
var whichFeed = \$(this).attr("rel");
|
||||
\$.ajax({
|
||||
var whichFeed = jQuery(this).attr("rel");
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "del_rss_feed",
|
||||
data: {feed: whichFeed, apikey: "$apikey" }
|
||||
@@ -570,9 +600,9 @@ function urlencode(str) {
|
||||
}
|
||||
});
|
||||
|
||||
\$('.toggleFeedCheckbox').click(function(){
|
||||
var whichFeed = \$(this).attr("rel");
|
||||
\$.ajax({
|
||||
jQuery('.toggleFeedCheckbox').click(function(){
|
||||
var whichFeed = jQuery(this).attr("rel");
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "toggle_rss_feed",
|
||||
data: {feed: whichFeed, apikey: "$apikey" }
|
||||
@@ -585,34 +615,34 @@ function urlencode(str) {
|
||||
});
|
||||
|
||||
// Only the Accept filter needs all the options
|
||||
\$('form[action="upd_rss_filter"]').find('select[name="filter_type"]').change(function() {
|
||||
\$(this).parent().parent().find('select:not([name="filter_type"])').attr('disabled', \$(this).val() != "A" && \$(this).val() != "S")
|
||||
jQuery('form[action="upd_rss_filter"]').find('select[name="filter_type"]').change(function() {
|
||||
jQuery(this).parent().parent().find('select:not([name="filter_type"])').attr('disabled', jQuery(this).val() !== "A" && jQuery(this).val() !== "S")
|
||||
})
|
||||
// Trigger on-load for all
|
||||
\$('.disabled_options_rule').find('td select:not([name="filter_type"])').attr('disabled', true)
|
||||
jQuery('.disabled_options_rule').find('td select:not([name="filter_type"])').attr('disabled', true)
|
||||
|
||||
function setActiveIcon(objButton) {
|
||||
// Let's make it look like things are happening!
|
||||
\$(objButton).attr('disabled', true)
|
||||
\$(objButton).find('span').remove()
|
||||
\$(objButton).prepend('<span class="glyphicon glyphicon-transfer"></span>')
|
||||
jQuery(objButton).attr('disabled', true)
|
||||
jQuery(objButton).find('span').remove()
|
||||
jQuery(objButton).prepend('<span class="glyphicon glyphicon-transfer"></span>')
|
||||
}
|
||||
|
||||
// Enable sorting and set default
|
||||
if (\$('#rss-tab-matched table').length) {
|
||||
\$('#rss-tab-matched table').tablesort().data('tablesort').sort(\$('#rss-tab-matched th.default-sort'), 'desc');
|
||||
if (jQuery('#rss-tab-matched table').length) {
|
||||
jQuery('#rss-tab-matched table').tablesort().data('tablesort').sort(jQuery('#rss-tab-matched th.default-sort'), 'desc');
|
||||
}
|
||||
if (\$('#rss-tab-not-matched table').length) {
|
||||
\$('#rss-tab-not-matched table').tablesort().data('tablesort').sort(\$('#rss-tab-not-matched th.default-sort'), 'desc');
|
||||
if (jQuery('#rss-tab-not-matched table').length) {
|
||||
jQuery('#rss-tab-not-matched table').tablesort().data('tablesort').sort(jQuery('#rss-tab-not-matched th.default-sort'), 'desc');
|
||||
}
|
||||
if (\$('#rss-tab-done table').length) {
|
||||
\$('#rss-tab-done table').tablesort().data('tablesort').sort(\$('#rss-tab-done th.default-sort'), 'desc');
|
||||
if (jQuery('#rss-tab-done table').length) {
|
||||
jQuery('#rss-tab-done table').tablesort().data('tablesort').sort(jQuery('#rss-tab-done th.default-sort'), 'desc');
|
||||
}
|
||||
|
||||
\$('.testFeed').click(function(){
|
||||
jQuery('.testFeed').click(function(){
|
||||
setActiveIcon(this)
|
||||
var whichFeed = \$(this).attr("rel");
|
||||
\$.ajax({
|
||||
var whichFeed = jQuery(this).attr("rel");
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "test_rss_feed",
|
||||
data: {feed: whichFeed, apikey: "$apikey" }
|
||||
@@ -624,34 +654,34 @@ function urlencode(str) {
|
||||
});
|
||||
});
|
||||
|
||||
\$('.cleanFeed').click(function(){
|
||||
jQuery('.cleanFeed').click(function(){
|
||||
setActiveIcon(this)
|
||||
var theForm = \$(this).closest("form");
|
||||
var theForm = jQuery(this).closest("form");
|
||||
theForm.attr("action", "clean_rss_jobs").submit();
|
||||
});
|
||||
|
||||
\$('.evalFeed').click(function(){
|
||||
jQuery('.evalFeed').click(function(){
|
||||
setActiveIcon(this)
|
||||
var theForm = \$(this).closest("form");
|
||||
var theForm = jQuery(this).closest("form");
|
||||
theForm.attr("action", "eval_rss_feed").submit();
|
||||
});
|
||||
|
||||
\$('.delFilter').click(function(){
|
||||
var theForm = \$(this).closest("form");
|
||||
jQuery('.delFilter').click(function(){
|
||||
var theForm = jQuery(this).closest("form");
|
||||
theForm.attr("action", "del_rss_filter").submit();
|
||||
});
|
||||
|
||||
\$('form[action="download"]').ajaxForm({
|
||||
jQuery('form[action="download"]').ajaxForm({
|
||||
datatype: 'json',
|
||||
beforeSubmit: function (_, form) {
|
||||
\$(form).find('button').attr("disabled", "disabled")
|
||||
jQuery(form).find('button').attr("disabled", "disabled")
|
||||
// Remove icon and add new one
|
||||
\$(form).find('button span').remove()
|
||||
\$(form).find('button').prepend('<span class="glyphicon glyphicon-transfer"></span>')
|
||||
jQuery(form).find('button span').remove()
|
||||
jQuery(form).find('button').prepend('<span class="glyphicon glyphicon-transfer"></span>')
|
||||
},
|
||||
success: function (_, _, _, form) {
|
||||
// Set success
|
||||
\$(form).find('button').html('<span class="glyphicon glyphicon-ok"></span> $T('rss-added')')
|
||||
jQuery(form).find('button').html('<span class="glyphicon glyphicon-ok"></span> $T('rss-added')')
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Scheduling"#-->
|
||||
<!--#set global $help_uri="configuration/3.0/scheduling"#-->
|
||||
<!--#set global $help_uri = $confighelpuri + "scheduling"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<%
|
||||
@@ -15,7 +15,7 @@ else:
|
||||
<div class="colmask">
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('addSchedule') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3>$T('addSchedule') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<form action="addSchedule" method="post" autocomplete="off">
|
||||
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
|
||||
@@ -50,7 +50,7 @@ else:
|
||||
<select name="action" id="action">
|
||||
<optgroup label="$T('sch-action')">
|
||||
<!--#for $action in $actions#-->
|
||||
<option value="$action" data-action="" data-noarg="<!--#if $action is 'speedlimit' then 0 else 1#-->">$actions_lng[$action]</option>
|
||||
<option value="$action" data-action="" data-noarg="<!--#if $action == 'speedlimit' then 0 else 1#-->">$actions_lng[$action]</option>
|
||||
<!--#end for#-->
|
||||
</optgroup>
|
||||
<optgroup label="$T('cmenu-servers')">
|
||||
@@ -112,32 +112,32 @@ else:
|
||||
</div><!-- /section -->
|
||||
</div><!-- /colmask -->
|
||||
<script type="text/javascript">
|
||||
\$('#action').on('change', function() {
|
||||
jQuery('#action').on('change', function() {
|
||||
// Set the action
|
||||
\$('#arguments').val((\$(this).find('option:selected').data('action')))
|
||||
jQuery('#arguments').val((jQuery(this).find('option:selected').data('action')))
|
||||
|
||||
// Is it speedlimit?
|
||||
if(\$(this).find('option:selected').val() == 'speedlimit') {
|
||||
\$('#hidden_arguments').show()
|
||||
\$('#hidden_arguments input').attr('placeholder', 'Bytes/s, "1M" = 1 MB/s, "500K" = 500 KB/s')
|
||||
if(jQuery(this).find('option:selected').val() === 'speedlimit') {
|
||||
jQuery('#hidden_arguments').show()
|
||||
jQuery('#hidden_arguments input').attr('placeholder', 'Bytes/s, "1M" = 1 MB/s, "500K" = 500 KB/s')
|
||||
} else {
|
||||
\$('#hidden_arguments').hide()
|
||||
\$('#hidden_arguments input').attr('placeholder', '')
|
||||
jQuery('#hidden_arguments').hide()
|
||||
jQuery('#hidden_arguments input').attr('placeholder', '')
|
||||
}
|
||||
|
||||
/* Arguments - since we only have speedlimit with arguments, disabled for now
|
||||
if(\$(this).find('option:selected').data('noarg')) {
|
||||
\$('#hidden_arguments').hide()
|
||||
if(jQuery(this).find('option:selected').data('noarg')) {
|
||||
jQuery('#hidden_arguments').hide()
|
||||
} else {
|
||||
\$('#hidden_arguments').show()
|
||||
jQuery('#hidden_arguments').show()
|
||||
}*/
|
||||
})
|
||||
|
||||
\$('[name="schedenabled"]').click(function() {
|
||||
\$.ajax({
|
||||
jQuery('[name="schedenabled"]').click(function() {
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "toggleSchedule",
|
||||
data: {line: \$(this).val(), apikey: "$apikey" }
|
||||
data: {line: jQuery(this).val(), apikey: "$apikey" }
|
||||
}).done(function() {
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
|
||||
@@ -1,51 +1,25 @@
|
||||
<!--#set global $pane="Servers"#-->
|
||||
<!--#set global $help_uri="configuration/3.0/servers"#-->
|
||||
<!--#set global $help_uri = $confighelpuri + "servers"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<!--
|
||||
We need to find how many months we have recorded so far, so we
|
||||
loop over all the dates to find the lowest value and then use
|
||||
this to calculate the date-selector and maximum value per month.
|
||||
-->
|
||||
<!--#import json#-->
|
||||
<!--#import datetime#-->
|
||||
<!--#import sabnzbd.misc#-->
|
||||
|
||||
<!--#set month_names = [$T('January'), $T('February'), $T('March'), $T('April'), $T('May'), $T('June'), $T('July'), $T('August'), $T('September'), $T('October'), $T('November'), $T('December')] #-->
|
||||
<!--#set min_date = datetime.date.today()#-->
|
||||
<!--#set max_data_all = {}#-->
|
||||
|
||||
<!--#for $server in $servers #-->
|
||||
<!--#if 'amounts' in $server#-->
|
||||
<!--#set max_data_server = {}#-->
|
||||
<!--#for date in $server['amounts'][4]#-->
|
||||
<!--#set split_date = $date.split('-')#-->
|
||||
<!--#set min_date = min(min_date, datetime.date(int(split_date[0]), int(split_date[1]), 1))#-->
|
||||
|
||||
<!--#set month_date = $date[:7]#-->
|
||||
<!--#if $month_date not in $max_data_server#-->
|
||||
<!--#set max_data_server[$month_date] = 0#-->
|
||||
<!--#end if#-->
|
||||
<!--#set max_data_server[$month_date] = max(max_data_server[$month_date], $server['amounts'][4][$date])#-->
|
||||
<!--#end for#-->
|
||||
|
||||
<!--#for month_date in max_data_server#-->
|
||||
<!--#if $month_date not in $max_data_all#-->
|
||||
<!--#set max_data_all[$month_date] = 0#-->
|
||||
<!--#end if#-->
|
||||
<!--#set max_data_all[$month_date] = max(max_data_all[$month_date], max_data_server[$month_date])#-->
|
||||
<!--#end for#-->
|
||||
<!--#end if#-->
|
||||
<!--#end for#-->
|
||||
|
||||
<!--#set months_recorded = list(sabnzbd.misc.monthrange(min_date, datetime.date.today()))#-->
|
||||
<!--#$months_recorded.reverse()#-->
|
||||
|
||||
<script type="text/javascript">
|
||||
// Define variable needed for the server-plots
|
||||
var serverData = {}
|
||||
// Define variable needed for the server-statistics
|
||||
var serverBandwithData = {}
|
||||
var serverArticleTries = {}
|
||||
var serverArticleFailed = {}
|
||||
|
||||
// Keep track of all used hostnames
|
||||
var hostnames = ""
|
||||
</script>
|
||||
|
||||
<div class="server-frame">
|
||||
<a href="#">×</a>
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
|
||||
<div class="colmask">
|
||||
<div class="padding alt section">
|
||||
<button type="button" class="btn btn-default" id="addServerButton"><span class="glyphicon glyphicon-plus"></span> $T('button-addServer')</button>
|
||||
@@ -53,60 +27,57 @@
|
||||
<input type="checkbox" id="advanced-settings-button" name="advanced-settings-button"> $T('button-advanced')
|
||||
</label>
|
||||
|
||||
<!--#if $months_recorded#-->
|
||||
<div class="advanced-buttonSeperator"></div>
|
||||
<div class="chart-selector-container" title="$T('srv-bandwidth')">
|
||||
<div class="chart-selector-container" title="$T('selectedDates')" data-placement="bottom">
|
||||
<span class="glyphicon glyphicon-signal"></span>
|
||||
<select name="chart-selector" id="chart-selector">
|
||||
<!--#for $cur_date in months_recorded#-->
|
||||
<!--#set month_date = '%d-%02d' % ($cur_date.year, $cur_date.month)#-->
|
||||
<!--#if $month_date not in $max_data_all#-->
|
||||
<!--#set max_data_all[$month_date] = 0#-->
|
||||
<!--#end if#-->
|
||||
<option value="$month_date" data-max="$max_data_all[$month_date]">$month_names[$cur_date.month-1] $cur_date.year</option>
|
||||
<!--#end for#-->
|
||||
</select>
|
||||
<!--#set today = datetime.date.today()#-->
|
||||
<input type="date" name="chart-start" id="chart-start" value="<!--#echo (today-datetime.timedelta(days=30)).strftime('%Y-%m-%d')#-->"> -
|
||||
<input type="date" name="chart-end" id="chart-end" value="<!--#echo today.strftime('%Y-%m-%d')#-->">
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
<div class="section" id="addServerContent" style="display: none;">
|
||||
<div class="col2">
|
||||
<h3>$T('addServer') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3>$T('addServer') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div>
|
||||
<div class="col1">
|
||||
<form action="addServer" method="post" autocomplete="off" onsubmit="removeObfuscation();">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="enable">$T('srv-enable')</label>
|
||||
<input type="checkbox" name="enable" id="enable" value="1" checked="checked" />
|
||||
<span class="desc">$T('srv-enable')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="displayname">$T('srv-displayname')</label>
|
||||
<input type="text" name="displayname" id="displayname" />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="host">$T('srv-host')</label>
|
||||
<input type="text" name="host" id="host" required />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="port">$T('srv-port')</label>
|
||||
<input type="number" name="port" id="port" size="8" value="119" min="0" />
|
||||
<input type="number" name="port" id="port" size="8" value="563" min="0" max="65535" />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="ssl">$T('srv-ssl')</label>
|
||||
<input type="checkbox" name="ssl" id="ssl" value="1" />
|
||||
<input type="checkbox" name="ssl" id="ssl" value="1" checked />
|
||||
<span class="desc">$T('explain-ssl')</span>
|
||||
</div>
|
||||
<!-- Tricks to avoid browser auto-fill, fixed on-submit with javascript -->
|
||||
<div class="field-pair">
|
||||
<label class="config" for="${pid}_00">$T('srv-username')</label>
|
||||
<input type="text" name="${pid}_00" id="${pid}_00" data-hide="username" />
|
||||
<label class="config" for="${pid}_000">$T('srv-username')</label>
|
||||
<input type="text" name="${pid}_000" id="${pid}_000" data-hide="username" />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="${pid}_01">$T('srv-password')</label>
|
||||
<input type="text" name="${pid}_01" id="${pid}_01" data-hide="password" />
|
||||
<label class="config" for="${pid}_001">$T('srv-password')</label>
|
||||
<input type="text" name="${pid}_001" id="${pid}_001" data-hide="password" />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="connections">$T('srv-connections')</label>
|
||||
<input type="number" name="connections" id="connections" min="1" max="100" value="8" required />
|
||||
<input type="number" name="connections" id="connections" min="1" max="500" value="8" required />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="priority">$T('srv-priority')</label>
|
||||
@@ -120,25 +91,26 @@
|
||||
<label class="config" for="timeout">$T('srv-timeout')</label>
|
||||
<input type="number" name="timeout" id="timeout" min="20" max="240" /> <i>$T('seconds')</i>
|
||||
</div>
|
||||
<div class="field-pair <!--#if int($certificate_validation) == 0 then "disabled" else ""#--> advanced-settings">
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="ssl_verify">$T('opt-ssl_verify')</label>
|
||||
<select name="ssl_verify" id="ssl_verify" <!--#if int($certificate_validation) == 0 then "disabled=\"disabled\"" else ""#-->>
|
||||
<option value="2" selected>$T('ssl_verify-strict')</option>
|
||||
<option value="1">$T('ssl_verify-normal')</option>
|
||||
<select name="ssl_verify" id="ssl_verify">
|
||||
<option value="3" selected>$T('ssl_verify-strict')</option>
|
||||
<option value="2">$T('ssl_verify-medium')</option>
|
||||
<option value="1">$T('ssl_verify-minimal')</option>
|
||||
<option value="0">$T('ssl_verify-disabled')</option>
|
||||
</select>
|
||||
<span class="desc">$T('explain-ssl_verify').replace('. ', '.<br/>')</span>
|
||||
<span class="desc">$T('explain-ssl_verify').replace('-', '<br/>-')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="ssl_ciphers">$T('opt-ssl_ciphers')</label>
|
||||
<input type="text" name="ssl_ciphers" id="ssl_ciphers" />
|
||||
<span class="desc">$T('explain-ssl_ciphers') <br>$T('readwiki')
|
||||
<a href="${helpuri}advanced/ssl-ciphers" target="_blank">${helpuri}advanced/ssl-ciphers</a></span>
|
||||
<a href="https://sabnzbd.org/wiki/advanced/ssl-ciphers" target="_blank">https://sabnzbd.org/wiki/advanced/ssl-ciphers</a></span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="send_group">$T('srv-send_group')</label>
|
||||
<input type="checkbox" name="send_group" id="send_group" value="1" />
|
||||
<span class="desc">$T('srv-explain-send_group')</span>
|
||||
<label class="config" for="required">$T('srv-required')</label>
|
||||
<input type="checkbox" name="required" id="required" value="1" />
|
||||
<span class="desc">$T('explain-required')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="optional">$T('srv-optional')</label>
|
||||
@@ -146,15 +118,27 @@
|
||||
<span class="desc">$T('explain-optional')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="displayname">$T('srv-displayname')</label>
|
||||
<input type="text" name="displayname" id="displayname" />
|
||||
<label class="config" for="pipelining_requests">$T('srv-pipelining_requests')</label>
|
||||
<input type="number" name="pipelining_requests" id="pipelining_requests" min="1" max="20" value="1" />
|
||||
<span class="desc">$T('explain-pipelining_requests')<br>$T('readwiki')
|
||||
<a href="https://sabnzbd.org/wiki/advanced/nntp-pipelining" target="_blank">https://sabnzbd.org/wiki/advanced/nntp-pipelining</a></span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="expire_date">$T('srv-expire_date')</label>
|
||||
<input type="date" name="expire_date" id="expire_date" />
|
||||
<span class="desc">$T('srv-explain-expire_date')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="quota">$T('swtag-quota')</label>
|
||||
<input type="text" name="quota" id="quota" class="smaller_input" />
|
||||
<span class="desc">$T('srv-explain-quota')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="notes">$T('srv-notes')</label>
|
||||
<textarea name="notes" id="notes" rows="3" cols="50"></textarea>
|
||||
</div>
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> $T('button-addServer')</button>
|
||||
<button class="btn btn-default addNewServer" disabled data-toggle="tooltip" data-placement="top" title="$T('wizard-test-server-required')"><span class="glyphicon glyphicon-plus"></span> $T('button-addServer')</button>
|
||||
<button class="btn btn-default testServer" type="button"><span class="glyphicon glyphicon-sort"></span> $T('button-testServer')</button>
|
||||
</div>
|
||||
<div class="field-pair result-box">
|
||||
@@ -165,18 +149,19 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--#set $prio_colors = ["#59cc33", "#3366cc","#7f33cc", "#cc33a6", "#cc3333"] #-->
|
||||
<!--#set $prio_colors = ["#59cc33", "#26a69a", "#3366cc", "#7f33cc", "#cc33a6", "#f39c12", "#cc3333", "#8d6e63"] #-->
|
||||
<!--#set $cur_prio_color = -1 #-->
|
||||
<!--#set $last_prio = -1 #-->
|
||||
<!--#for $cur, $server in enumerate($servers) #-->
|
||||
<form action="saveServer" method="post" class="fullform" autocomplete="off">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<input type="hidden" name="server" value="$server['name']" />
|
||||
<input type="hidden" id="ajax" name="ajax" value=1 />
|
||||
<input type="hidden" name="ajax" value=1 />
|
||||
|
||||
<div class="section <!--#if int($server['enable']) == 0 then 'server-disabled' else ""#-->">
|
||||
<div class="col2 <!--#if int($server['enable']) == 0 then 'server-disabled' else ""#-->">
|
||||
<h3>$server['displayname'] <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3 title="$server['displayname']">$server['displayname'] <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<!--#if int($server['enable']) != 0 #-->
|
||||
<!--#if $last_prio != $server['priority'] and $cur_prio_color+1 < len($prio_colors) #-->
|
||||
<!--#set $cur_prio_color = $cur_prio_color+1 #-->
|
||||
@@ -193,17 +178,24 @@
|
||||
</table>
|
||||
<button type="button" class="btn btn-default showserver"><span class="glyphicon glyphicon-pencil"></span> $T('showDetails')</button>
|
||||
<button type="button" class="btn btn-default clrServer"><span class="glyphicon glyphicon-remove"></span> $T('button-clrServer')</button>
|
||||
<!--#if $server['notes'] #-->
|
||||
<p>$server['notes'].replace('\n', '<br>')</p>
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
<div class="col1" style="display:none;">
|
||||
<input type="hidden" name="enable" id="enable$cur" value="$int($server['enable'])" />
|
||||
<fieldset>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="displayname$cur">$T('srv-displayname')</label>
|
||||
<input type="text" name="displayname" id="displayname$cur" value="$server['displayname']" />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="host$cur">$T('srv-host')</label>
|
||||
<input type="text" name="host" id="host$cur" value="$server['host']" required />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="port$cur">$T('srv-port')</label>
|
||||
<input type="number" name="port" id="port$cur" value="$server['port']" size="8" min="0" required />
|
||||
<input type="number" name="port" id="port$cur" value="$server['port']" size="8" min="0" max="65535" required />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="ssl$cur">$T('srv-ssl')</label>
|
||||
@@ -221,7 +213,7 @@
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="connections$cur">$T('srv-connections')</label>
|
||||
<input type="number" name="connections" id="connections$cur" value="$server['connections']" min="1" max="100" required />
|
||||
<input type="number" name="connections" id="connections$cur" value="$server['connections']" min="1" max="500" required />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="priority$cur">$T('srv-priority')</label>
|
||||
@@ -236,20 +228,26 @@
|
||||
<input type="number" name="timeout" id="timeout$cur" value="$server['timeout']" min="20" max="240" required /> <i>$T('seconds')</i>
|
||||
</div>
|
||||
|
||||
<div class="field-pair <!--#if int($certificate_validation) == 0 then "disabled" else ""#--> advanced-settings">
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="ssl_verify$cur">$T('opt-ssl_verify')</label>
|
||||
<select name="ssl_verify" id="ssl_verify$cur" <!--#if int($certificate_validation) == 0 then "disabled=\"disabled\"" else ""#-->>
|
||||
<option value="2" <!--#if $server['ssl_verify'] == 2 then 'selected="selected"' else ""#--> >$T('ssl_verify-strict')</option>
|
||||
<option value="1" <!--#if $server['ssl_verify'] == 1 then 'selected="selected"' else ""#--> >$T('ssl_verify-normal')</option>
|
||||
<select name="ssl_verify" id="ssl_verify$cur">
|
||||
<option value="3" <!--#if $server['ssl_verify'] == 3 then 'selected="selected"' else ""#--> >$T('ssl_verify-strict')</option>
|
||||
<option value="2" <!--#if $server['ssl_verify'] == 2 then 'selected="selected"' else ""#--> >$T('ssl_verify-medium')</option>
|
||||
<option value="1" <!--#if $server['ssl_verify'] == 1 then 'selected="selected"' else ""#--> >$T('ssl_verify-minimal')</option>
|
||||
<option value="0" <!--#if $server['ssl_verify'] == 0 then 'selected="selected"' else ""#--> >$T('ssl_verify-disabled')</option>
|
||||
</select>
|
||||
<span class="desc">$T('explain-ssl_verify').replace('. ', '.<br/>')</span>
|
||||
<span class="desc">$T('explain-ssl_verify').replace('-', '<br/>-')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="ssl_ciphers">$T('opt-ssl_ciphers')</label>
|
||||
<input type="text" name="ssl_ciphers" id="ssl_ciphers" value="$server['ssl_ciphers']" />
|
||||
<label class="config" for="ssl_ciphers$cur">$T('opt-ssl_ciphers')</label>
|
||||
<input type="text" name="ssl_ciphers" id="ssl_ciphers$cur" value="$server['ssl_ciphers']" />
|
||||
<span class="desc">$T('explain-ssl_ciphers') <br>$T('readwiki')
|
||||
<a href="${helpuri}advanced/ssl-ciphers" target="_blank">${helpuri}advanced/ssl-ciphers</a></span>
|
||||
<a href="https://sabnzbd.org/wiki/advanced/ssl-ciphers" target="_blank">https://sabnzbd.org/wiki/advanced/ssl-ciphers</a></span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="required$cur">$T('srv-required')</label>
|
||||
<input type="checkbox" name="required" id="required$cur" value="1" <!--#if int($server['required']) != 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-required')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="optional$cur">$T('srv-optional')</label>
|
||||
@@ -257,19 +255,26 @@
|
||||
<span class="desc">$T('explain-optional')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="send_group$cur">$T('srv-send_group')</label>
|
||||
<input type="checkbox" name="send_group" id="send_group$cur" value="1" <!--#if int($server['send_group']) != 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('srv-explain-send_group')</span>
|
||||
<label class="config" for="pipelining_requests$cur">$T('srv-pipelining_requests')</label>
|
||||
<input type="number" name="pipelining_requests" id="pipelining_requests$cur" value="$server['pipelining_requests']" min="1" max="20" required />
|
||||
<span class="desc">$T('explain-pipelining_requests')<br>$T('readwiki')
|
||||
<a href="https://sabnzbd.org/wiki/advanced/nntp-pipelining" target="_blank">https://sabnzbd.org/wiki/advanced/nntp-pipelining</a></span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="displayname$cur">$T('srv-displayname')</label>
|
||||
<input type="text" name="displayname" id="displayname$cur" value="$server['displayname']" />
|
||||
<label class="config" for="expire_date$cur">$T('srv-expire_date')</label>
|
||||
<input type="date" name="expire_date" id="expire_date$cur" value="$server['expire_date']" />
|
||||
<span class="desc">$T('srv-explain-expire_date')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="quota$cur">$T('swtag-quota')</label>
|
||||
<input type="text" name="quota" id="quota$cur" value="$server['quota']" class="smaller_input" />
|
||||
<span class="desc">$T('srv-explain-quota')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="notes$cur">$T('srv-notes')</label>
|
||||
<textarea name="notes" id="notes$cur" rows="3" cols="50">$server['notes']</textarea>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default testServer" type="button"><span class="glyphicon glyphicon-sort"></span> $T('button-testServer')</button>
|
||||
<button class="btn btn-default delServer"><span class="glyphicon glyphicon-trash"></span> $T('button-delServer')</button>
|
||||
@@ -282,19 +287,38 @@
|
||||
<div class="col1" style="display:block;">
|
||||
<!--#if 'amounts' in $server#-->
|
||||
<div class="server-amounts-text">
|
||||
<b>$T('srv-bandwidth'):</b><br/>
|
||||
$T('total'): $(server['amounts'][0])B<br/>
|
||||
$T('today'): $(server['amounts'][3])B<br/>
|
||||
$T('thisWeek'): $(server['amounts'][2])B<br/>
|
||||
$T('thisMonth'): $(server['amounts'][1])B<br/>
|
||||
<span id="server-data-label-${cur}"></span>: <span id="server-data-value-${cur}"></span>
|
||||
<p>
|
||||
<b>$T('srv-bandwidth'):</b><br/>
|
||||
$T('total'): $(server['amounts'][0])B<br/>
|
||||
$T('today'): $(server['amounts'][3])B<br/>
|
||||
$T('thisWeek'): $(server['amounts'][2])B<br/>
|
||||
$T('thisMonth'): $(server['amounts'][1])B<br/>
|
||||
$T('selectedDates'): <span id="server-bandwith-value-${cur}"></span>
|
||||
</p>
|
||||
|
||||
<p title="$T('readwiki')">
|
||||
<b>$T('srv-article-availability'):</b><br/>
|
||||
$T('selectedDates'): <span id="server-article-value-${cur}"></span><br/>
|
||||
<a href="https://sabnzbd.org/not-complete" id="server-article-not-complete-${cur}" target="_blank">https://sabnzbd.org/not-complete</a>
|
||||
</p>
|
||||
<!--#if $server['expire_date']#-->
|
||||
<p><b>$T('srv-expire_date'):</b> $(server['expire_date'])</p>
|
||||
<!--#end if#-->
|
||||
<!--#if $server['quota']#-->
|
||||
<p><b>$T('quota-left'):</b> $(server['quota_left'])</p>
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
<div class="server-chart" data-serverid="${cur}"s>
|
||||
<div class="server-chart" data-serverid="${cur}">
|
||||
<div id="server-chart-${cur}" class="ct-chart"></div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
// Server data
|
||||
serverData[${cur}] = <!--#echo json.dumps($server['amounts'][4])#-->
|
||||
serverBandwithData[${cur}] = <!--#echo json.dumps($server['amounts'][4])#-->
|
||||
serverArticleTries[${cur}] = <!--#echo json.dumps($server['amounts'][5])#-->
|
||||
serverArticleFailed[${cur}] = <!--#echo json.dumps($server['amounts'][6])#-->
|
||||
<!--#if int($server['enable']) != 0#-->
|
||||
hostnames += ",$server['host']"
|
||||
<!--#end if#-->
|
||||
</script>
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
@@ -331,58 +355,94 @@
|
||||
}
|
||||
|
||||
function showCharts() {
|
||||
// This month
|
||||
var theMonth = \$('#chart-selector').val()
|
||||
var thisDay = new Date()
|
||||
// Get the constants
|
||||
const startDate = new Date(jQuery('#chart-start').val())
|
||||
const endDate = new Date(jQuery('#chart-end').val())
|
||||
const oneDay = 24 * 60 * 60 * 1000
|
||||
const nrDays = Math.round((endDate-startDate)/oneDay)
|
||||
|
||||
// What month are we doing?
|
||||
var inputDate = new Date(theMonth+'-01')
|
||||
var baseDate = new Date(inputDate.getUTCFullYear(), inputDate.getUTCMonth(), 1)
|
||||
var maxDaysInMonth = new Date(baseDate.getFullYear(), baseDate.getMonth()+1, 0).getDate()
|
||||
// Show only maximum 10 labels to avoid cluttering
|
||||
const labelStep = Math.round(nrDays/10)
|
||||
|
||||
// Set the new maximum
|
||||
chartOptions.axisY.high = \$('#chart-selector :selected').data('max');
|
||||
chartOptions.axisY.low = 0
|
||||
// Save largest value
|
||||
var maxBandwith = 0
|
||||
|
||||
// For each chart
|
||||
\$('.server-chart').each(function(i, elemn) {
|
||||
var server_id = \$(elemn).data('serverid')
|
||||
jQuery('.server-chart').each(function(j, elemn) {
|
||||
const server_id = jQuery(elemn).data('serverid')
|
||||
var totalBandwithThisRange = 0
|
||||
var totalArticlesTriedThisRange = 0
|
||||
var totalArticlesFailedThisRange = 0
|
||||
|
||||
// Fill the data array
|
||||
var data = {
|
||||
labels: [],
|
||||
series: [[]]
|
||||
};
|
||||
var totalThisMonth = 0
|
||||
for(var i = 1; i < maxDaysInMonth+1; i++) {
|
||||
|
||||
for(var i = 0; i < nrDays+1; i++) {
|
||||
// Update the date
|
||||
const checkDate = new Date(startDate)
|
||||
checkDate.setDate(checkDate.getDate() + i);
|
||||
|
||||
// Add X-label
|
||||
if(i % 3 == 1) {
|
||||
data['labels'].push(i)
|
||||
if(i % labelStep === 0) {
|
||||
data['labels'].push(checkDate.getDate())
|
||||
} else {
|
||||
data['labels'].push(NaN)
|
||||
}
|
||||
|
||||
// Get formatted date
|
||||
baseDate.setDate(i)
|
||||
var dateCheck = toFormattedDate(baseDate)
|
||||
// Date we can check in the array
|
||||
const dateCheck = toFormattedDate(checkDate)
|
||||
|
||||
// Add data if we have it
|
||||
if(dateCheck in serverData[server_id]) {
|
||||
data['series'][0].push(serverData[server_id][dateCheck])
|
||||
totalThisMonth += serverData[server_id][dateCheck]
|
||||
} else if(thisDay.getYear() == baseDate.getYear() && thisDay.getMonth() == baseDate.getMonth() && thisDay.getDate() < i) {
|
||||
data['series'][0].push(NaN)
|
||||
if(dateCheck in serverBandwithData[server_id]) {
|
||||
data['series'][0].push(serverBandwithData[server_id][dateCheck])
|
||||
totalBandwithThisRange += serverBandwithData[server_id][dateCheck]
|
||||
maxBandwith = Math.max(maxBandwith, serverBandwithData[server_id][dateCheck])
|
||||
} else {
|
||||
data['series'][0].push(0)
|
||||
}
|
||||
|
||||
// Article stats
|
||||
if(dateCheck in serverArticleTries[server_id]) {
|
||||
totalArticlesTriedThisRange += serverArticleTries[server_id][dateCheck]
|
||||
totalArticlesFailedThisRange += serverArticleFailed[server_id][dateCheck]
|
||||
}
|
||||
}
|
||||
|
||||
// Update the text value
|
||||
\$('#server-data-label-' + server_id).text(\$('#chart-selector :selected').text())
|
||||
\$('#server-data-value-' + server_id).text(filesize(totalThisMonth, {round: 1}))
|
||||
jQuery('#server-bandwith-value-' + server_id).text(filesize(totalBandwithThisRange, {round: 1}))
|
||||
|
||||
// Calculate article success ratio, if available
|
||||
var articleRatio = Math.round(100 * (1 - totalArticlesFailedThisRange/totalArticlesTriedThisRange))
|
||||
|
||||
// If values were missing
|
||||
if(!isNaN(articleRatio)) {
|
||||
// Use filesize to convert to unit-display
|
||||
jQuery('#server-article-value-' + server_id).text('$T("srv-articles-tried")'.replace('%f', articleRatio).replace('%d', filesize(totalArticlesTriedThisRange, {unix: true, round: 0, spacer: "", base: 1})))
|
||||
// If we have a low value, we link them to the website
|
||||
if(articleRatio > 60) jQuery('#server-article-not-complete-' + server_id).hide()
|
||||
} else {
|
||||
jQuery('#server-article-value-' + server_id).text('$T("notAvailable")')
|
||||
jQuery('#server-article-not-complete-' + server_id).hide()
|
||||
}
|
||||
|
||||
// Save bandwidth data in a very ugly way, but we need to do this
|
||||
// so we can calculate the maximum Y-axis for all graphs
|
||||
jQuery(elemn).data("chart-data", data)
|
||||
})
|
||||
|
||||
// Set the maximum
|
||||
chartOptions.axisY.high = maxBandwith
|
||||
chartOptions.axisY.low = 0
|
||||
|
||||
// Update all the axis with the largest value and draw the graph
|
||||
jQuery('.server-chart').each(function(j, elemn) {
|
||||
const server_id = jQuery(elemn).data('serverid')
|
||||
|
||||
// Show the chart
|
||||
chart = new Chartist.Line('#server-chart-'+server_id, data, chartOptions);
|
||||
chart = new Chartist.Line('#server-chart-'+server_id, jQuery(elemn).data("chart-data"), chartOptions)
|
||||
chart.on('created', function(context) {
|
||||
// Make sure to add this as the first child so it's at the bottom
|
||||
context.svg.elem('rect', {
|
||||
@@ -391,14 +451,18 @@
|
||||
width: context.chartRect.width(),
|
||||
height: context.chartRect.height()+2,
|
||||
fill: 'none',
|
||||
stroke: '#B9B9B9',
|
||||
stroke: '#b9b9b9',
|
||||
'stroke-width': '1px'
|
||||
}, '', context.svg, true)
|
||||
\$('#server-chart-'+server_id+' .ct-label.ct-vertical').each(function(index, elmn) {
|
||||
jQuery('#server-chart-'+server_id+' .ct-label.ct-vertical').each(function(index, elmn) {
|
||||
elmn.innerHTML = filesize(elmn.innerHTML, {round: 1}).replace(' ','')
|
||||
})
|
||||
});
|
||||
})
|
||||
|
||||
// Limit input to sensible values
|
||||
jQuery('#chart-start').attr("max", jQuery('#chart-end').val())
|
||||
jQuery('#chart-end').attr("min", jQuery('#chart-start').val())
|
||||
}
|
||||
|
||||
// Need to mitigate timezone effects!
|
||||
@@ -411,21 +475,21 @@
|
||||
/**
|
||||
When finished loading
|
||||
**/
|
||||
\$(document).ready(function(){
|
||||
// Exception when change of priority, reload
|
||||
\$('input[name="priority"], input[name="displayname"]').on('change', function() {
|
||||
\$('.fullform').submit(function() {
|
||||
// No ajax this time
|
||||
\$('input[name="ajax"]').val('')
|
||||
// Skip the fancy stuff, just submit
|
||||
this.submit()
|
||||
})
|
||||
jQuery(document).ready(function(){
|
||||
// Initialize tooltips
|
||||
jQuery('[data-toggle="tooltip"]').tooltip()
|
||||
|
||||
// Reload form in case we change items that make the servers appear different
|
||||
jQuery('input[name="priority"], input[name="displayname"], textarea[name="notes"]').on('change', function(event) {
|
||||
var parentForm = jQuery(event.target).parents("form")
|
||||
parentForm.unbind("submit")
|
||||
parentForm.find('input[name="ajax"]').val('')
|
||||
})
|
||||
|
||||
/**
|
||||
Update charts when changed
|
||||
**/
|
||||
\$('#chart-selector').on('change', function(elemn) {
|
||||
jQuery('#chart-start, #chart-end').on('change', function(elemn) {
|
||||
showCharts()
|
||||
|
||||
// Lets us leave (needs to be called after the change event)
|
||||
@@ -440,16 +504,16 @@
|
||||
/**
|
||||
Click events
|
||||
**/
|
||||
\$('.showserver').click(function () {
|
||||
if(\$(this).parent().hasClass('server-disabled')) {
|
||||
\$(this).parent().parent().toggleClass('server-disabled')
|
||||
jQuery('.showserver').click(function () {
|
||||
if(jQuery(this).parent().hasClass('server-disabled')) {
|
||||
jQuery(this).parent().parent().toggleClass('server-disabled')
|
||||
}
|
||||
\$(this).parent().next().toggle();
|
||||
\$(this).parent().next().next().toggle();
|
||||
if (\$(this).text().indexOf("$T('showDetails')") > 0) {
|
||||
\$(this).html(\$(this).html().replace("$T('showDetails')", "$T('hideDetails')"));
|
||||
jQuery(this).parent().next().toggle();
|
||||
jQuery(this).parent().next().next().toggle();
|
||||
if (jQuery(this).text().indexOf("$T('showDetails')") > 0) {
|
||||
jQuery(this).html(jQuery(this).html().replace("$T('showDetails')", "$T('hideDetails')"));
|
||||
} else {
|
||||
\$(this).html(\$(this).html().replace("$T('hideDetails')", "$T('showDetails')"));
|
||||
jQuery(this).html(jQuery(this).html().replace("$T('hideDetails')", "$T('showDetails')"));
|
||||
// Recalculate the charts if changed while details were open
|
||||
showCharts()
|
||||
}
|
||||
@@ -457,24 +521,24 @@
|
||||
addRowColor()
|
||||
});
|
||||
|
||||
\$('#addServerButton').click(function(){
|
||||
\$('#addServerContent').show();
|
||||
jQuery('#addServerButton').click(function(){
|
||||
jQuery('#addServerContent').show();
|
||||
// Add coloring
|
||||
addRowColor()
|
||||
});
|
||||
|
||||
\$('[name="ssl"]').click(function() {
|
||||
jQuery('[name="ssl"]').click(function() {
|
||||
// Use CSS transitions to do some highlighting
|
||||
var portBox = \$(this).parent().parent().find('[name="port"]')
|
||||
var portBox = jQuery(this).parent().parent().find('[name="port"]')
|
||||
if(this.checked) {
|
||||
// Enabled SSL change port when not already a custom port
|
||||
if(portBox.val() == '119') {
|
||||
if(portBox.val() === '119') {
|
||||
portBox.val('563')
|
||||
portBox.addClass('port-highlight')
|
||||
}
|
||||
} else {
|
||||
// Remove SSL port
|
||||
if(portBox.val() == '563') {
|
||||
if(portBox.val() === '563') {
|
||||
portBox.val('119')
|
||||
portBox.addClass('port-highlight')
|
||||
}
|
||||
@@ -483,16 +547,16 @@
|
||||
})
|
||||
|
||||
// Testing servers
|
||||
\$('.testServer').click(function(event){
|
||||
jQuery('.testServer').click(function(event){
|
||||
removeObfuscation()
|
||||
var theButton = \$(this)
|
||||
var theButton = jQuery(this)
|
||||
var resultBox = theButton.parents('.col1').find('.result-box .alert');
|
||||
theButton.attr("disabled", "disabled")
|
||||
theButton.find('span').toggleClass('glyphicon-sort glyphicon-refresh spin-glyphicon')
|
||||
\$.ajax({
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "../../api",
|
||||
data: "mode=config&output=json&name=test_server&" + \$(this).parents('form:first').serialize()
|
||||
data: "mode=config&name=test_server&" + jQuery(this).parents('form:first').serialize()
|
||||
}).then(function(data) {
|
||||
// Let's replace the link
|
||||
msg = data.value.message.replace('https://sabnzbd.org/certificate-errors', '<a href="https://sabnzbd.org/certificate-errors" class="alert-link" target="_blank">https://sabnzbd.org/certificate-errors</a>')
|
||||
@@ -503,20 +567,37 @@
|
||||
theButton.removeAttr("disabled")
|
||||
theButton.find('span').toggleClass('glyphicon-sort glyphicon-refresh spin-glyphicon')
|
||||
|
||||
// Succes or not?
|
||||
// Success or not?
|
||||
if(data.value.result) {
|
||||
resultBox.addClass('alert-success')
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-ok-sign"></span> ')
|
||||
|
||||
// Allow adding the new server if we are in the new-server section
|
||||
if(theButton.parents("form[action='addServer']").length) {
|
||||
jQuery(".addNewServer").removeAttr("disabled")
|
||||
jQuery(".addNewServer").removeAttr("data-toggle")
|
||||
jQuery(".addNewServer").removeAttr("title")
|
||||
jQuery(".addNewServer").tooltip("destroy")
|
||||
}
|
||||
} else {
|
||||
resultBox.addClass('alert-danger')
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ')
|
||||
|
||||
// Disable the adding of new server, just to be sure
|
||||
if(theButton.parents("form[action='addServer']").length) {
|
||||
jQuery(".addNewServer").attr("disabled", "disabled")
|
||||
jQuery(".addNewServer").attr("data-toggle", "tooltip")
|
||||
jQuery(".addNewServer").attr("data-placement", "top")
|
||||
jQuery(".addNewServer").attr("title", "$T('wizard-test-server-required')")
|
||||
jQuery(".addNewServer").tooltip()
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
\$('.delServer').click(function(){
|
||||
if( confirm("$T('Plush-confirm')") ) {
|
||||
\$(this).parents('form:first').attr('action','delServer').submit();
|
||||
jQuery('.delServer').click(function(){
|
||||
if( confirm("$T('confirm')") ) {
|
||||
jQuery(this).parents('form:first').attr('action','delServer').submit();
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
formHasChanged = false;
|
||||
@@ -525,9 +606,9 @@
|
||||
return false;
|
||||
});
|
||||
|
||||
\$('.clrServer').click(function(){
|
||||
if( confirm("$T('Plush-confirm')") ) {
|
||||
\$(this).parents('form:first').attr('action','clrServer').submit();
|
||||
jQuery('.clrServer').click(function(){
|
||||
if( confirm("$T('confirm')") ) {
|
||||
jQuery(this).parents('form:first').attr('action','clrServer').submit();
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
formHasChanged = false;
|
||||
@@ -536,9 +617,9 @@
|
||||
return false;
|
||||
});
|
||||
|
||||
\$('.toggleServerCheckbox').click(function(){
|
||||
var whichServer = \$(this).attr("name");
|
||||
\$.ajax({
|
||||
jQuery('.toggleServerCheckbox').click(function(){
|
||||
var whichServer = jQuery(this).attr("name");
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "toggleServer",
|
||||
data: {server: whichServer, apikey: "$apikey" }
|
||||
@@ -549,6 +630,35 @@
|
||||
setTimeout(function() { location.reload(); }, 100)
|
||||
});
|
||||
});
|
||||
|
||||
// Show text-ad if there is space
|
||||
if((jQuery("body").width() - jQuery("#content").width())/2 > (jQuery('.Servers .server-frame').width() + 40)) {
|
||||
// Do not show if dismissed previously
|
||||
if(localStorage.getItem("server-frame-hide-$version") === null) {
|
||||
// Let the page on the server tell us if we need to show
|
||||
function receiveMessage(event) {
|
||||
// Check origin of message for security reasons
|
||||
if(event.origin === 'https://sabnzbd.org') {
|
||||
if(event.data === 'show_server') {
|
||||
jQuery('.Servers .server-frame').show()
|
||||
jQuery('.Servers .server-frame a').click(function () {
|
||||
localStorage.setItem("server-frame-hide-$version", "hide")
|
||||
jQuery('.Servers .server-frame').hide()
|
||||
})
|
||||
}
|
||||
if(event.data === 'hide_server') {
|
||||
// Hide and don't load anymore until the next release
|
||||
jQuery('.Servers .server-frame').hide()
|
||||
localStorage.setItem("server-frame-hide-$version", "hide")
|
||||
}
|
||||
}
|
||||
}
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
|
||||
// NOTE: The hash-part cannot be seen by the server, so we don't know which hostnames you use!
|
||||
jQuery('.Servers .server-frame iframe').attr("src", "https://sabnzbd.org/servers#$active_lang" + hostnames)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Special"#-->
|
||||
<!--#set global $help_uri="configuration/3.0/special"#-->
|
||||
<!--#set global $help_uri = $confighelpuri + "special"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<div class="colmask">
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('sptag-boolean') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3>$T('sptag-boolean') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
@@ -33,7 +33,7 @@
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('sptag-entries') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3>$T('sptag-entries') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Switches"#-->
|
||||
<!--#set global $help_uri="configuration/3.0/switches"#-->
|
||||
<!--#set global $help_uri = $confighelpuri + "switches"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<div class="colmask">
|
||||
@@ -10,21 +10,14 @@
|
||||
</div>
|
||||
<form action="saveSwitches" method="post" name="fullform" class="fullform" autocomplete="off">
|
||||
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
|
||||
<input type="hidden" id="ajax" name="ajax" value="1" />
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<div class="section advanced-settings">
|
||||
<div class="col2">
|
||||
<h3>$T('swtag-server') <a href="$helpuri$help_uri#toc1" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3>$T('swtag-server') <a href="$help_uri#toc1" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="load_balancing">$T('opt-load_balancing')</label>
|
||||
<select name="load_balancing" id="load_balancing">
|
||||
<option value="0" <!--#if $load_balancing == 0 then 'selected="selected"' else ""#--> >$T('no-load-balancing')</option>
|
||||
<option value="1" <!--#if $load_balancing == 1 then 'selected="selected"' else ""#--> >$T('load-balancing')</option>
|
||||
<option value="2" <!--#if $load_balancing == 2 then 'selected="selected"' else ""#--> >$T('load-balancing-happy-eyeballs')</option>
|
||||
</select>
|
||||
<span class="desc">$T('explain-load_balancing')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="max_art_tries">$T('opt-max_art_tries')</label>
|
||||
<input type="number" name="max_art_tries" id="max_art_tries" value="$max_art_tries" min="2" max="2000" />
|
||||
@@ -44,11 +37,11 @@
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('swtag-queue') <a href="$helpuri$help_uri#toc2" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3>$T('swtag-queue') <a href="$help_uri#toc2" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="pre_script">$T('opt-pre_script')</label>
|
||||
<select name="pre_script" id="pre_script">
|
||||
<!--#for $sc in $scripts#-->
|
||||
@@ -61,9 +54,22 @@
|
||||
</select>
|
||||
<span class="desc">$T('explain-pre_script')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="end_queue_script">$T('opt-end_queue_script')</label>
|
||||
<select name="end_queue_script" id="end_queue_script">
|
||||
<!--#for $sc in $scripts#-->
|
||||
<!--#if $sc.lower() == $end_queue_script.lower()#-->
|
||||
<option value="$sc" selected="selected">$Tspec($sc)</option>
|
||||
<!--#else#-->
|
||||
<option value="$sc">$Tspec($sc)</option>
|
||||
<!--#end if#-->
|
||||
<!--#end for#-->
|
||||
</select>
|
||||
<span class="desc">$T('explain-end_queue_script')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="propagation_delay">$T('opt-propagation_delay')</label>
|
||||
<input type="number" name="propagation_delay" id="propagation_delay" value="$propagation_delay" /> <i>$T('minutes')</i>
|
||||
<input type="number" name="propagation_delay" id="propagation_delay" value="$propagation_delay" min="0" /> <i>$T('minutes')</i>
|
||||
<span class="desc">$T('explain-propagation_delay')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
@@ -87,38 +93,48 @@
|
||||
<option value="0" <!--#if int($no_dupes) == 0 then 'selected="selected"' else ""#--> >$T('nodupes-off')</option>
|
||||
<option value="4" <!--#if int($no_dupes) == 4 then 'selected="selected"' else ""#--> >$T('nodupes-tag')</option>
|
||||
<option value="2" <!--#if int($no_dupes) == 2 then 'selected="selected"' else ""#--> >$T('nodupes-pause')</option>
|
||||
<option value="3" <!--#if int($no_dupes) == 3 then 'selected="selected"' else ""#--> >$T('nodupes-fail')</option>
|
||||
<option value="3" <!--#if int($no_dupes) == 3 then 'selected="selected"' else ""#--> >$T('fail-to-history')</option>
|
||||
<option value="1" <!--#if int($no_dupes) == 1 then 'selected="selected"' else ""#--> >$T('nodupes-ignore')</option>
|
||||
</select>
|
||||
<span class="desc">$T('explain-no_dupes')</span>
|
||||
<span class="desc">
|
||||
$T('explain-no_dupes')<br>
|
||||
<a href="https://sabnzbd.org/wiki/duplicate-detection" target="_blank">https://sabnzbd.org/wiki/duplicate-detection</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="no_series_dupes">$T('opt-no_series_dupes')</label>
|
||||
<select name="no_series_dupes" id="no_series_dupes">
|
||||
<option value="0" <!--#if int($no_series_dupes) == 0 then 'selected="selected"' else ""#--> >$T('nodupes-off')</option>
|
||||
<option value="4" <!--#if int($no_series_dupes) == 4 then 'selected="selected"' else ""#--> >$T('nodupes-tag')</option>
|
||||
<option value="2" <!--#if int($no_series_dupes) == 2 then 'selected="selected"' else ""#--> >$T('nodupes-pause')</option>
|
||||
<option value="3" <!--#if int($no_series_dupes) == 3 then 'selected="selected"' else ""#--> >$T('nodupes-fail')</option>
|
||||
<option value="1" <!--#if int($no_series_dupes) == 1 then 'selected="selected"' else ""#--> >$T('nodupes-ignore')</option>
|
||||
<label class="config" for="no_smart_dupes">$T('opt-no_smart_dupes')</label>
|
||||
<select name="no_smart_dupes" id="no_smart_dupes">
|
||||
<option value="0" <!--#if int($no_smart_dupes) == 0 then 'selected="selected"' else ""#--> >$T('nodupes-off')</option>
|
||||
<option value="4" <!--#if int($no_smart_dupes) == 4 then 'selected="selected"' else ""#--> >$T('nodupes-tag')</option>
|
||||
<option value="2" <!--#if int($no_smart_dupes) == 2 then 'selected="selected"' else ""#--> >$T('nodupes-pause')</option>
|
||||
<option value="3" <!--#if int($no_smart_dupes) == 3 then 'selected="selected"' else ""#--> >$T('fail-to-history')</option>
|
||||
<option value="1" <!--#if int($no_smart_dupes) == 1 then 'selected="selected"' else ""#--> >$T('nodupes-ignore')</option>
|
||||
</select>
|
||||
<span class="desc">$T('explain-no_series_dupes')</span>
|
||||
<span class="desc">
|
||||
$T('explain-no_smart_dupes')<br>
|
||||
<a href="https://sabnzbd.org/wiki/duplicate-detection" target="_blank">https://sabnzbd.org/wiki/duplicate-detection</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="series_propercheck">$T('opt-series_propercheck')</label>
|
||||
<input type="checkbox" name="series_propercheck" id="series_propercheck" value="1" <!--#if int($series_propercheck) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-series_propercheck')</span>
|
||||
<label class="config" for="dupes_propercheck">$T('opt-dupes_propercheck')</label>
|
||||
<input type="checkbox" name="dupes_propercheck" id="dupes_propercheck" value="1" <!--#if int($dupes_propercheck) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-dupes_propercheck')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="pause_on_pwrar">$T('opt-pause_on_pwrar')</label>
|
||||
<select name="pause_on_pwrar" id="pause_on_pwrar">
|
||||
<option value="0" <!--#if int($pause_on_pwrar) == 0 then 'selected="selected"' else ""#--> >$T('nodupes-off')</option>
|
||||
<option value="1" <!--#if int($pause_on_pwrar) == 1 then 'selected="selected"' else ""#--> >$T('nodupes-pause')</option>
|
||||
<option value="2" <!--#if int($pause_on_pwrar) == 2 then 'selected="selected"' else ""#--> >$T('abort')</option>
|
||||
<option value="2" <!--#if int($pause_on_pwrar) == 2 then 'selected="selected"' else ""#--> >$T('fail-to-history')</option>
|
||||
</select>
|
||||
<span class="desc">$T('explain-pause_on_pwrar')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="unwanted_extensions">$T('opt-unwanted_extensions')</label>
|
||||
<select name="unwanted_extensions_mode" id="unwanted_extensions_mode">
|
||||
<option value="0" <!--#if int($unwanted_extensions_mode) == 0 then 'selected="selected"' else ""#--> >$T('unwanted_extensions_blacklist')</option>
|
||||
<option value="1" <!--#if int($unwanted_extensions_mode) == 1 then 'selected="selected"' else ""#--> >$T('unwanted_extensions_whitelist')</option>
|
||||
</select>
|
||||
<input type="text" name="unwanted_extensions" id="unwanted_extensions" value="$unwanted_extensions"/>
|
||||
<span class="desc">$T('explain-unwanted_extensions')</span>
|
||||
</div>
|
||||
@@ -127,14 +143,23 @@
|
||||
<select name="action_on_unwanted_extensions" id="action_on_unwanted_extensions">
|
||||
<option value="0" <!--#if int($action_on_unwanted_extensions) == 0 then 'selected="selected"' else ""#--> >$T('nodupes-off')</option>
|
||||
<option value="1" <!--#if int($action_on_unwanted_extensions) == 1 then 'selected="selected"' else ""#--> >$T('nodupes-pause')</option>
|
||||
<option value="2" <!--#if int($action_on_unwanted_extensions) == 2 then 'selected="selected"' else ""#--> >$T('abort')</option>
|
||||
<option value="2" <!--#if int($action_on_unwanted_extensions) == 2 then 'selected="selected"' else ""#--> >$T('fail-to-history')</option>
|
||||
</select>
|
||||
<span class="desc">$T('explain-action_on_unwanted_extensions')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="auto_sort">$T('opt-auto_sort')</label>
|
||||
<input type="checkbox" name="auto_sort" id="auto_sort" value="1" <!--#if int($auto_sort) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-auto_sort')</span>
|
||||
<select name="auto_sort" id="auto_sort">
|
||||
<option value="">$T('default')</option>
|
||||
<option value="remaining asc" <!--#if $auto_sort == "remaining asc" then 'selected="selected"' else ""#--> >$T('Glitter-sortRemaining')</option>
|
||||
<option value="avg_age desc" <!--#if $auto_sort == "avg_age desc" then 'selected="selected"' else ""#--> >$T('Glitter-sortAgeAsc')</option>
|
||||
<option value="avg_age asc" <!--#if $auto_sort == "avg_age asc" then 'selected="selected"' else ""#--> >$T('Glitter-sortAgeDesc')</option>
|
||||
<option value="name asc" <!--#if $auto_sort == "name asc" then 'selected="selected"' else ""#--> >$T('Glitter-sortNameAsc')</option>
|
||||
<option value="name desc" <!--#if $auto_sort == "name desc" then 'selected="selected"' else ""#--> >$T('Glitter-sortNameDesc')</option>
|
||||
<option value="size asc" <!--#if $auto_sort == "size asc" then 'selected="selected"' else ""#--> >$T('Glitter-sortSizeAsc')</option>
|
||||
<option value="size desc" <!--#if $auto_sort == "size desc" then 'selected="selected"' else ""#--> >$T('Glitter-sortSizeDesc')</option>
|
||||
</select>
|
||||
<span class="desc">$T('explain-auto_sort') $T('explain-auto_sort_remaining')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="direct_unpack">$T('opt-direct_unpack')</label>
|
||||
@@ -150,7 +175,7 @@
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('swtag-pp') <a href="$helpuri$help_uri#toc3" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3>$T('swtag-pp') <a href="$help_uri#toc3" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
@@ -164,16 +189,16 @@
|
||||
<input type="checkbox" name="enable_all_par" id="enable_all_par" value="1" <!--#if int($enable_all_par) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-enable_all_par').replace('. ', '.<br/>')</span>
|
||||
</div>
|
||||
<!--#if not $nt#-->
|
||||
<!--#if not $windows#-->
|
||||
<div class="field-pair advanced-settings <!--#if not $have_nice then "disabled" else "" #-->">
|
||||
<label class="config" for="nice">$T('opt-nice')</label>
|
||||
<input type="text" name="nice" id="nice" value="$nice" <!--#if not $have_nice then 'readonly="readonly" disabled="disabled"' else "" #--> />
|
||||
<span class="desc">$T('explain-nice')</span>
|
||||
<span class="desc">$T('readwiki')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings <!--#if not $have_ionice then "disabled" else "" #-->">
|
||||
<label class="config" for="ionice">$T('opt-ionice')</label>
|
||||
<input type="text" name="ionice" id="ionice" value="$ionice" <!--#if not $have_ionice then 'readonly="readonly" disabled="disabled"' else "" #--> />
|
||||
<span class="desc">$T('explain-ionice')</span>
|
||||
<span class="desc">$T('readwiki')</span>
|
||||
</div>
|
||||
<!--#else#-->
|
||||
<div class="field-pair advanced-settings">
|
||||
@@ -185,13 +210,13 @@
|
||||
<option value="2" <!--#if int($win_process_prio) == 2 then 'selected="selected"' else ""#-->>$T('win_process_prio-low')</option>
|
||||
<option value="1" <!--#if int($win_process_prio) == 1 then 'selected="selected"' else ""#-->>$T('win_process_prio-idle')</option>
|
||||
</select>
|
||||
<span class="desc">$T('explain-win_process_prio')</span>
|
||||
<span class="desc">$T('readwiki')</span>
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="par_option">$T('opt-par_option')</label>
|
||||
<input type="text" name="par_option" id="par_option" value="$par_option" />
|
||||
<span class="desc">$T('explain-par_option')</span>
|
||||
<span class="desc">$T('readwiki')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="sfv_check">$T('opt-sfv_check')</label>
|
||||
@@ -218,20 +243,15 @@
|
||||
<input type="checkbox" name="script_can_fail" id="script_can_fail" value="1" <!--#if int($script_can_fail) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-script_can_fail')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="new_nzb_on_failure">$T('opt-new_nzb_on_failure')</label>
|
||||
<input type="checkbox" name="new_nzb_on_failure" id="new_nzb_on_failure" value="1" <!--#if int($new_nzb_on_failure) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-new_nzb_on_failure')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="ignore_samples">$T('opt-ignore_samples')</label>
|
||||
<input type="checkbox" name="ignore_samples" id="ignore_samples" value="1" <!--#if int($ignore_samples) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-ignore_samples') $T('igsam-del').</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="enable_meta">$T('opt-enable_meta')</label>
|
||||
<input type="checkbox" name="enable_meta" id="enable_meta" value="1" <!--#if int($enable_meta) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-enable_meta').replace('. ', '.<br/>')</span>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="deobfuscate_final_filenames">$T('opt-deobfuscate_final_filenames')</label>
|
||||
<input type="checkbox" name="deobfuscate_final_filenames" id="deobfuscate_final_filenames" value="1" <!--#if int($deobfuscate_final_filenames) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-deobfuscate_final_filenames') $T('explain-deobfuscate_final_filenames-ext')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="cleanup_list">$T('opt-cleanup_list')</label>
|
||||
@@ -239,16 +259,17 @@
|
||||
<span class="desc">$T('explain-cleanup_list')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="history_retention_select">$T('opt-history_retention')</label>
|
||||
<input type="hidden" name="history_retention" id="history_retention" value="$history_retention">
|
||||
<select name="history_retention_select" id="history_retention_select">
|
||||
<option value="0">$T('history_retention-all')</option>
|
||||
<option value="n">$T('history_retention-number')</option>
|
||||
<option value="d">$T('history_retention-days')</option>
|
||||
<option value="-1">$T('history_retention-none')</option>
|
||||
<label class="config" for="history_retention_option">$T('opt-history_retention')</label>
|
||||
<select name="history_retention_option" id="history_retention_option">
|
||||
<option value="all" <!--#if $auto_sort == "all" then 'selected="selected"' else ""#-->>$T('history_retention-all')</option>
|
||||
<option value="number-archive" <!--#if $history_retention_option == "number-archive" then 'selected="selected"' else ""#-->>$T('history_retention-number-archive')</option>
|
||||
<option value="number-delete" <!--#if $history_retention_option == "number-delete" then 'selected="selected"' else ""#-->>$T('history_retention-number-delete')</option>
|
||||
<option value="days-archive" <!--#if $history_retention_option == "days-archive" then 'selected="selected"' else ""#-->>$T('history_retention-days-archive')</option>
|
||||
<option value="days-delete" <!--#if $history_retention_option == "days-delete" then 'selected="selected"' else ""#-->>$T('history_retention-days-delete')</option>
|
||||
<option value="all-archive" <!--#if $history_retention_option == "all-archive" then 'selected="selected"' else ""#-->>$T('history_retention-archive')</option>
|
||||
<option value="all-delete" <!--#if $history_retention_option == "all-delete" then 'selected="selected"' else ""#-->>$T('history_retention-none')</option>
|
||||
</select>
|
||||
<input type="number" id="history_retention_number" name="history_retention_number" min="1">
|
||||
<span class="desc">$T('explain-history_retention').replace('. ', '.<br/>')</span>
|
||||
<input type="number" id="history_retention_number" name="history_retention_number" min="1" value="$history_retention_number">
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
@@ -259,7 +280,7 @@
|
||||
</div><!-- /section -->
|
||||
<div class="section advanced-settings">
|
||||
<div class="col2">
|
||||
<h3>$T('swtag-naming') <a href="$helpuri$help_uri#toc4" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3>$T('swtag-naming') <a href="$help_uri#toc4" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
@@ -273,12 +294,17 @@
|
||||
<input type="checkbox" name="replace_spaces" id="replace_spaces" value="1" <!--#if int($replace_spaces) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-replace_spaces')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="replace_underscores">$T('opt-replace_underscores')</label>
|
||||
<input type="checkbox" name="replace_underscores" id="replace_underscores" value="1" <!--#if int($replace_underscores) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-replace_underscores')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="replace_dots">$T('opt-replace_dots')</label>
|
||||
<input type="checkbox" name="replace_dots" id="replace_dots" value="1" <!--#if int($replace_dots) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-replace_dots')</span>
|
||||
</div>
|
||||
<!--#if not $nt#-->
|
||||
<!--#if not $windows#-->
|
||||
<div class="field-pair">
|
||||
<label class="config" for="sanitize_safe">$T('opt-sanitize_safe')</label>
|
||||
<input type="checkbox" name="sanitize_safe" id="sanitize_safe" value="1" <!--#if int($sanitize_safe) > 0 then 'checked="checked"' else ""#--> />
|
||||
@@ -294,7 +320,7 @@
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('swtag-quota') <a href="$helpuri$help_uri#toc5" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<h3>$T('swtag-quota') <a href="$help_uri#toc5" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
@@ -329,199 +355,33 @@
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('swtag-indexing') <a href="$helpuri$help_uri#toc6" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="rating_enable">$T('opt-rating_enable')</label>
|
||||
<input type="checkbox" name="rating_enable" id="rating_enable" value="1" <!--#if int($rating_enable) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-rating_enable').replace('. ', '.<br/>')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="rating_api_key">$T('opt-rating_api_key')</label>
|
||||
<input type="text" name="rating_api_key" id="rating_api_key" value="$rating_api_key" />
|
||||
<span class="desc">$T('explain-rating_api_key')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="rating_filter_enable">$T('opt-rating_filter_enable')</label>
|
||||
<input type="checkbox" name="rating_filter_enable" id="rating_filter_enable" value="1" <!--#if int($rating_filter_enable) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-rating_filter_enable')</span>
|
||||
</div>
|
||||
<div class="field-pair" id="rating_filter_abort">
|
||||
<label class="config">$T('opt-rating_filter_abort_if')</label>
|
||||
<div class="rating-filter">
|
||||
<p>
|
||||
<label for="rating_filter_abort_video">$T('opt-rating_filter_video')</label>
|
||||
<select name="rating_filter_abort_video" id="rating_filter_abort_video">
|
||||
<option value="0" <!--#if $rating_filter_abort_video == 0 then 'selected="selected"' else ""#--> >$T('notUsed')</option>
|
||||
<!--#for $val in $range(1, 10)#--><option value="$val" <!--#if $rating_filter_abort_video == $val then 'selected="selected"' else ""#--> >$val $T('orLess')</option><!--#end for#-->
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="rating_filter_abort_audio">$T('opt-rating_filter_audio')</label>
|
||||
<select name="rating_filter_abort_audio" id="rating_filter_abort_audio">
|
||||
<option value="0" <!--#if $rating_filter_abort_audio == 0 then 'selected="selected"' else ""#--> >$T('notUsed')</option>
|
||||
<!--#for $val in $range(1, 10)#--><option value="$val" <!--#if $rating_filter_abort_audio == $val then 'selected="selected"' else ""#--> >$val $T('orLess')</option><!--#end for#-->
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_abort_encrypted" name="rating_filter_abort_encrypted" <!--#if int($rating_filter_abort_encrypted) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_abort_encrypted">$T('opt-rating_filter_passworded')</label>
|
||||
</span>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_abort_encrypted_confirm" name="rating_filter_abort_encrypted_confirm" <!--#if int($rating_filter_abort_encrypted_confirm) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_abort_encrypted_confirm">$T('opt-rating_filter_confirmed')</label>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_abort_spam" name="rating_filter_abort_spam" <!--#if int($rating_filter_abort_spam) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_abort_spam">$T('opt-rating_filter_spam')</label>
|
||||
</span>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_abort_spam_confirm" name="rating_filter_abort_spam_confirm" <!--#if int($rating_filter_abort_spam_confirm) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_abort_spam_confirm">$T('opt-rating_filter_confirmed')</label>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<input type="checkbox" value="1" id="rating_filter_abort_downvoted" name="rating_filter_abort_downvoted" <!--#if int($rating_filter_abort_downvoted) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_abort_downvoted">$T('opt-rating_filter_downvoted')</label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="rating_filter_abort_keywords">$T('opt-rating_filter_keywords')</label>
|
||||
<input type="text" name="rating_filter_abort_keywords" id="rating_filter_abort_keywords" value="$rating_filter_abort_keywords"/>
|
||||
<span class="desc">$T('explain-rating_filter_keywords')</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-pair" id="rating_filter_pause">
|
||||
<label class="config">$T('opt-rating_filter_pause_if')</label>
|
||||
<div class="rating-filter">
|
||||
<p>
|
||||
<label for="rating_filter_pause_video">$T('opt-rating_filter_video')</label>
|
||||
<select name="rating_filter_pause_video" id="rating_filter_pause_video">
|
||||
<option value="0" <!--#if $rating_filter_pause_video == 0 then 'selected="selected"' else ""#--> >$T('notUsed')</option>
|
||||
<!--#for $val in $range(1, 10)#--><option value="$val" <!--#if $rating_filter_pause_video == $val then 'selected="selected"' else ""#--> >$val $T('orLess')</option><!--#end for#-->
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="rating_filter_pause_audio">$T('opt-rating_filter_audio')</label>
|
||||
<select name="rating_filter_pause_audio" id="rating_filter_pause_audio">
|
||||
<option value="0" <!--#if $rating_filter_pause_audio == 0 then 'selected="selected"' else ""#--> >$T('notUsed')</option>
|
||||
<!--#for $val in $range(1, 10)#--><option value="$val" <!--#if $rating_filter_pause_audio == $val then 'selected="selected"' else ""#--> >$val $T('orLess') </option><!--#end for#-->
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_pause_encrypted" name="rating_filter_pause_encrypted" <!--#if int($rating_filter_pause_encrypted) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_pause_encrypted">$T('opt-rating_filter_passworded')</label>
|
||||
</span>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_pause_encrypted_confirm" name="rating_filter_pause_encrypted_confirm" <!--#if int($rating_filter_pause_encrypted_confirm) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_pause_encrypted_confirm">$T('opt-rating_filter_confirmed')</label>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_pause_spam" name="rating_filter_pause_spam" <!--#if int($rating_filter_pause_spam) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_pause_spam">$T('opt-rating_filter_spam')</label>
|
||||
</span>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_pause_spam_confirm" name="rating_filter_pause_spam_confirm" <!--#if int($rating_filter_pause_spam_confirm) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_pause_spam_confirm">$T('opt-rating_filter_confirmed')</label>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<input type="checkbox" value="1" id="rating_filter_pause_downvoted" name="rating_filter_pause_downvoted" <!--#if int($rating_filter_pause_downvoted) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_pause_downvoted">$T('opt-rating_filter_downvoted')</label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="rating_filter_pause_keywords">$T('opt-rating_filter_keywords')</label>
|
||||
<input type="text" name="rating_filter_pause_keywords" id="rating_filter_pause_keywords" value="$rating_filter_pause_keywords"/>
|
||||
<span class="desc">$T('explain-rating_filter_keywords')</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
</form>
|
||||
</div><!-- /colmask -->
|
||||
|
||||
<script type="text/javascript">
|
||||
\$(document).ready(function() {
|
||||
if (!\$('#rating_filter_enable').is(":checked")) {
|
||||
\$("#rating_filter_abort").hide();
|
||||
\$("#rating_filter_pause").hide();
|
||||
}
|
||||
\$('#rating_filter_enable').change(function () {
|
||||
if (\$(this).is(":checked")) {
|
||||
\$("#rating_filter_abort").show();
|
||||
\$("#rating_filter_pause").show();
|
||||
}
|
||||
else {
|
||||
\$("#rating_filter_abort").hide();
|
||||
\$("#rating_filter_pause").hide();
|
||||
}
|
||||
});
|
||||
|
||||
\$('#history_retention_select, #history_retention_number').on('change', updateHistoryRetention)
|
||||
jQuery(document).ready(function() {
|
||||
jQuery('#history_retention_option').on('change', updateHistoryRetention)
|
||||
function updateHistoryRetention() {
|
||||
var retention_setting = \$('#history_retention')
|
||||
var retention_select = \$('#history_retention_select').val()
|
||||
var retention_number = \$('#history_retention_number')
|
||||
// Keep all or keep none
|
||||
if(retention_select == "0" || retention_select == "-1") {
|
||||
var retention_option = jQuery('#history_retention_option').val()
|
||||
var retention_number = jQuery('#history_retention_number')
|
||||
|
||||
if(retention_option === "number-archive" || retention_option === "number-delete") {
|
||||
retention_number.show()
|
||||
retention_number.attr('placeholder', '$T('history_retention-limit')')
|
||||
} else if(retention_option === "days-archive" || retention_option === "days-delete") {
|
||||
retention_number.show()
|
||||
retention_number.attr('placeholder', '$T('days').capitalize()')
|
||||
} else {
|
||||
retention_number.hide()
|
||||
retention_number.val('')
|
||||
retention_number.attr('placeholder', '')
|
||||
retention_setting.val(retention_select)
|
||||
} else {
|
||||
retention_number.show()
|
||||
// Days or number?
|
||||
if(retention_select.indexOf("d") !== -1) {
|
||||
retention_number.attr('placeholder', '$T('days').capitalize()')
|
||||
if(retention_number.val()) {
|
||||
retention_setting.val(retention_number.val() + 'd')
|
||||
} else if(parseInt(retention_setting.val()) > 0) {
|
||||
retention_number.val(parseInt(retention_setting.val()))
|
||||
}
|
||||
} else {
|
||||
retention_number.attr('placeholder', '$T('history_retention-limit')')
|
||||
if(retention_number.val()) {
|
||||
retention_setting.val(retention_number.val())
|
||||
} else if(parseInt(retention_setting.val()) > 0) {
|
||||
retention_number.val(parseInt(retention_setting.val()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set the history-retention settig
|
||||
var retention_setting_value = \$('#history_retention').val()
|
||||
if(parseInt(retention_setting_value) > 0) {
|
||||
// Days or number?
|
||||
if(retention_setting_value.indexOf("d") !== -1) {
|
||||
\$('#history_retention_select').val("d")
|
||||
} else {
|
||||
\$('#history_retention_select').val("n")
|
||||
}
|
||||
\$('#history_retention_number').val(parseInt(retention_setting_value))
|
||||
} else {
|
||||
// Keep all or keep none
|
||||
\$('#history_retention_select').val(retention_setting_value)
|
||||
\$('#history_retention_number').hide()
|
||||
}
|
||||
updateHistoryRetention()
|
||||
|
||||
\$('.restoreDefaults').click(function(e) {
|
||||
jQuery('.restoreDefaults').click(function(e) {
|
||||
// Get section name
|
||||
var sectionName = \$(this).parents('.section').find('.col2 h3').text().trim()
|
||||
var sectionName = jQuery(this).parents('.section').find('.col2 h3').text().trim()
|
||||
|
||||
// Confirm?
|
||||
if(!confirm("$T('explain-restoreDefaults') \""+sectionName+"\"\n$T('confirm')")) return false
|
||||
@@ -529,11 +389,11 @@
|
||||
|
||||
// Need to get all the input values, so same way as saving normally
|
||||
var key_container = {}
|
||||
\$(this).parents('.section').extractFormDataTo(key_container);
|
||||
jQuery(this).parents('.section').extractFormDataTo(key_container);
|
||||
key_container = Object.keys(key_container)
|
||||
|
||||
// Send request
|
||||
\$.ajax({
|
||||
jQuery.ajax({
|
||||
type: "GET",
|
||||
url: "../../api",
|
||||
data: "mode=set_config_default&apikey=${apikey}&output=json&keyword=" + key_container.join('&keyword=')
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="$active_lang">
|
||||
<head>
|
||||
<title>SABnzbd - $T('login')</title>
|
||||
@@ -15,8 +16,11 @@
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="../staticcfg/bootstrap/css/bootstrap.min.css?v=$version" />
|
||||
<link rel="stylesheet" type="text/css" href="../staticcfg/css/login.css?v=$version" />
|
||||
<!--#if $color_scheme not in ('Light', '') #-->
|
||||
<link rel="stylesheet" type="text/css" href="../staticcfg/css/${color_scheme}.css?v=$version"/>
|
||||
<!--#end if#-->
|
||||
|
||||
<script type="text/javascript" src="../staticcfg/js/jquery-3.2.1.min.js?v=$version"></script>
|
||||
<script type="text/javascript" src="../staticcfg/js/jquery-3.5.1.min.js?v=$version"></script>
|
||||
<script type="text/javascript" src="../staticcfg/bootstrap/js/bootstrap.min.js?v=$version"></script>
|
||||
</head>
|
||||
<html>
|
||||
@@ -33,8 +37,8 @@
|
||||
<div class="alert alert-danger" role="alert">$error</div>
|
||||
<!--#end if#-->
|
||||
|
||||
<input type="text" class="form-control" name="username" placeholder="$T('srv-username')" required autofocus>
|
||||
<input type="password" class="form-control" name="password" placeholder="$T('srv-password')" required>
|
||||
<input type="text" class="form-control" name="username" placeholder="$T('srv-username')" autocomplete="username" required autofocus>
|
||||
<input type="password" class="form-control" name="password" placeholder="$T('srv-password')" autocomplete="current-password" required>
|
||||
|
||||
<button class="btn btn-default"><span class="glyphicon glyphicon-circle-arrow-right"></span> $T('login') </button>
|
||||
|
||||
@@ -47,16 +51,16 @@
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
// Tooltip
|
||||
\$('[data-toggle="tooltip"]').tooltip()
|
||||
jQuery('[data-toggle="tooltip"]').tooltip()
|
||||
// Try-catch in case somebody disabled localstorage
|
||||
try {
|
||||
// Set what was done previously
|
||||
\$('input[type="checkbox"]').prop('checked', localStorage.getItem("remember_me") === 'true')
|
||||
jQuery('input[type="checkbox"]').prop('checked', localStorage.getItem("remember_me") === 'true')
|
||||
// Store if we change something
|
||||
\$('input[type="checkbox"]').on('change', function() {
|
||||
localStorage.setItem("remember_me", \$(this).is(':checked'));
|
||||
jQuery('input[type="checkbox"]').on('change', function() {
|
||||
localStorage.setItem("remember_me", jQuery(this).is(':checked'));
|
||||
})
|
||||
} catch(err) { }
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
File diff suppressed because one or more lines are too long
1
interfaces/Config/templates/staticcfg/css/Auto.css
Normal file
1
interfaces/Config/templates/staticcfg/css/Auto.css
Normal file
@@ -0,0 +1 @@
|
||||
@import url('Night.css') screen and (prefers-color-scheme: dark);
|
||||
298
interfaces/Config/templates/staticcfg/css/Night.css
Normal file
298
interfaces/Config/templates/staticcfg/css/Night.css
Normal file
@@ -0,0 +1,298 @@
|
||||
body {
|
||||
background-color: black;
|
||||
color: #EBEBEB !important;
|
||||
}
|
||||
|
||||
a:not(.btn) {
|
||||
color: #63a7e1;
|
||||
}
|
||||
|
||||
.btn {
|
||||
box-shadow: 1px 1px 1px rgba(255, 255, 255, .1) !important;
|
||||
}
|
||||
|
||||
.btn:not(.btn-danger),
|
||||
.btn-default,
|
||||
input,
|
||||
select,
|
||||
textarea,
|
||||
.advanced-button,
|
||||
.list-group-item {
|
||||
border-color: #252525 !important;
|
||||
}
|
||||
|
||||
#addFeed,
|
||||
#addFeedContent,
|
||||
.section {
|
||||
border-bottom: 1px solid #555555;
|
||||
}
|
||||
|
||||
.col2 p,
|
||||
.col2-cats {
|
||||
color: #AAA;
|
||||
}
|
||||
|
||||
.col2 h3 {
|
||||
background: none repeat scroll 0 0 #555555;
|
||||
}
|
||||
|
||||
.catTable,
|
||||
.dropdown-menu,
|
||||
.dropdown-menu .divider,
|
||||
.even,
|
||||
.Key tr:nth-child(odd),
|
||||
.language:hover,
|
||||
.navbar-default .navbar-nav>.open>a,
|
||||
.navbar-default .navbar-nav>.open>a:focus,
|
||||
.navbar-default .navbar-nav>.open>a:hover,
|
||||
.navbar-default .navbar-nav>li>a.active,
|
||||
.navbar-default .navbar-nav>li>a:hover,
|
||||
.navbar-default .navbar-nav>li>a:focus,
|
||||
.navbar-logo:hover,
|
||||
.quoteBlock,
|
||||
.server-disabled,
|
||||
#serverResponse,
|
||||
.table>tbody>tr:nth-child(odd),
|
||||
.table-striped>tbody>tr:nth-child(odd),
|
||||
ul.tabs li.active a,
|
||||
select[disabled],
|
||||
select:hover {
|
||||
background-color: #444444 !important;
|
||||
color: #EBEBEB !important;
|
||||
}
|
||||
|
||||
.failed {
|
||||
color: #ff3333 !important;
|
||||
}
|
||||
|
||||
#rightGreyText,
|
||||
small {
|
||||
color: #c7c7c7 !important;
|
||||
}
|
||||
|
||||
.Categories form.sorting-row:nth-child(2n-1) tr,
|
||||
.advanced-button,
|
||||
.advanced-buttonSeperator,
|
||||
.alt,
|
||||
.infoTableSeperator.alt,
|
||||
.btn:not(.btn-danger),
|
||||
.btn-default.disabled:active,
|
||||
.btn-default.disabled:focus,
|
||||
.btn-default.disabled:hover,
|
||||
a.btn.btn-default,
|
||||
select.form-control,
|
||||
.form-control[disabled],
|
||||
.input-group-addon,
|
||||
#inner,
|
||||
.navbar-default,
|
||||
.search-box input,
|
||||
.select,
|
||||
.table-striped>tbody>tr:nth-child(even),
|
||||
.table>tbody>tr:nth-child(even),
|
||||
.tab-pane tr:nth-child(odd),
|
||||
textarea,
|
||||
ul.tabs a.active,
|
||||
a.list-group-item,
|
||||
.dropdown-menu>li>a,
|
||||
input[type="text"],
|
||||
input[type="email"],
|
||||
input[type="url"],
|
||||
input[type="date"],
|
||||
input[type="number"],
|
||||
input[type="password"],
|
||||
input[disabled],
|
||||
textarea,
|
||||
select {
|
||||
background-color: #555555;
|
||||
color: #EBEBEB;
|
||||
}
|
||||
|
||||
.btn:hover:not(.btn-danger),
|
||||
.btn-default:hover,
|
||||
.tab-content .catTable tr:hover td,
|
||||
input:hover,
|
||||
textarea:hover,
|
||||
a.list-group-item:hover,
|
||||
select:hover,
|
||||
textarea:hover,
|
||||
input[type="date"]:hover,
|
||||
input[type="datetime"]:hover,
|
||||
input[type="datetime-local"]:hover,
|
||||
input[type="email"]:hover,
|
||||
input[type="month"]:hover,
|
||||
input[type="number"]:hover,
|
||||
input[type="password"]:hover,
|
||||
input[type="search"]:hover,
|
||||
input[type="tel"]:hover,
|
||||
input[type="text"]:hover,
|
||||
input[type="time"]:hover,
|
||||
input[type="url"]:hover,
|
||||
input[type="week"]:hover,
|
||||
textarea:focus,
|
||||
select:focus,
|
||||
input[type="date"]:focus,
|
||||
input[type="datetime"]:focus,
|
||||
input[type="datetime-local"]:focus,
|
||||
input[type="email"]:focus,
|
||||
input[type="month"]:focus,
|
||||
input[type="number"]:focus,
|
||||
input[type="password"]:focus,
|
||||
input[type="search"]:focus,
|
||||
input[type="tel"]:focus,
|
||||
input[type="text"]:focus,
|
||||
input[type="time"]:focus,
|
||||
input[type="url"]:focus,
|
||||
input[type="week"]:focus {
|
||||
background-color: #666;
|
||||
color: #EBEBEB;
|
||||
}
|
||||
|
||||
.btn-default:focus,
|
||||
.form-control:focus,
|
||||
input:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
border-color: #707070 !important;
|
||||
outline: initial !important;
|
||||
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
background-color: #262626 !important;
|
||||
}
|
||||
|
||||
.Key tr {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.table>tbody>tr>td,
|
||||
.table>tbody>tr>th,
|
||||
.infoTableSeperator,
|
||||
.modal-footer,
|
||||
.data-row {
|
||||
border-top: 1px solid #555555;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-top: 1px solid #555555;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
border-color: #7b2b28;
|
||||
}
|
||||
|
||||
.tab-content .catTable tbody,
|
||||
ul.tabs a,
|
||||
.colmask,
|
||||
#subscriptions,
|
||||
.RSS form[action="add_rss_feed"] tr:nth-child(even),
|
||||
.Config .table {
|
||||
border: 1px solid #555555;
|
||||
}
|
||||
|
||||
.Categories form:first-of-type tr:last-of-type,
|
||||
.default,
|
||||
.dropdown-menu>li>a:focus,
|
||||
.dropdown-menu>li>a:hover {
|
||||
background-color: #696969;
|
||||
}
|
||||
|
||||
.activeRSS,
|
||||
.activeRSS a,
|
||||
.activeRSS a:visited,
|
||||
.btn-default,
|
||||
.checkbox label,
|
||||
.feed-row td,
|
||||
.help-block,
|
||||
#content,
|
||||
.navbar-default .navbar-nav>li>a,
|
||||
.navbar-default .navbar-nav>li>a>.glyphicon,
|
||||
.path,
|
||||
.Servers .ct-label,
|
||||
.time,
|
||||
.main-restarting.in,
|
||||
#search-dropdown .dropdown-header,
|
||||
ul.tabs a,
|
||||
a.wizard-advanced-settings,
|
||||
.quoteBlock a,
|
||||
a.main-helplink,
|
||||
col2 h3 a,
|
||||
.text-center a,
|
||||
.text-center a:hover {
|
||||
color: #EBEBEB;
|
||||
}
|
||||
|
||||
.container,
|
||||
#content {
|
||||
background-color: unset !important;
|
||||
}
|
||||
|
||||
#content>div.colmask>div:nth-child(3) {
|
||||
border-bottom: 1px solid #555555 !important;
|
||||
}
|
||||
|
||||
.Servers .ct-series-a .ct-line,
|
||||
.Servers .ct-series-a .ct-point {
|
||||
stroke: #EBEBEB;
|
||||
}
|
||||
|
||||
#inner,
|
||||
.colmask {
|
||||
background-color: #303030;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
background-color: #3C3C3C;
|
||||
}
|
||||
|
||||
.modal-content,
|
||||
.modal-body,
|
||||
.modal-footer {
|
||||
background-color: #727272;
|
||||
}
|
||||
|
||||
#modal_qr .modal-body {
|
||||
background-color: #EBEBEB;
|
||||
}
|
||||
|
||||
.form-signin .btn.btn-default {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.rss-icon-svg {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
.rss-symbol {
|
||||
fill: #555555;
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: #EBEBEB !important;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
background-color: #E4E4E4 !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
/* for login */
|
||||
.tooltip.bottom .tooltip-arrow {
|
||||
border-bottom-color: #E4E4E4 !important;
|
||||
}
|
||||
/* config>general - host-warning */
|
||||
.tooltip.top .tooltip-arrow {
|
||||
border-top-color: #E4E4E4 !important;
|
||||
}
|
||||
|
||||
.tooltip.left .tooltip-arrow {
|
||||
border-left-color: #E4E4E4 !important;
|
||||
}
|
||||
|
||||
.tooltip.right .tooltip-arrow {
|
||||
border-right-color: #E4E4E4 !important;
|
||||
}
|
||||
|
||||
.Special .glyphicon-asterisk {
|
||||
color: #E4E4E4 !important;
|
||||
}
|
||||
@@ -7,7 +7,10 @@ body {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.btn, .btn:hover, .btn:active, .btn:focus {
|
||||
.btn,
|
||||
.btn:hover,
|
||||
.btn:active,
|
||||
.btn:focus {
|
||||
box-shadow: 1px 1px 1px rgba(0,0,0,.1) !important;
|
||||
background-color: white !important;
|
||||
}
|
||||
@@ -38,7 +41,7 @@ body {
|
||||
}
|
||||
|
||||
.text-center a:hover {
|
||||
color: black !important;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.form-signin .alert {
|
||||
|
||||
@@ -19,6 +19,7 @@ body {
|
||||
float: left;
|
||||
overflow: visible;
|
||||
border: 1px solid #dfdede;
|
||||
border-bottom: none !important;
|
||||
background-color: #FFF;
|
||||
width: 100%
|
||||
}
|
||||
@@ -89,15 +90,20 @@ body {
|
||||
display: block;
|
||||
position: static;
|
||||
float: right;
|
||||
color: black !important;
|
||||
color: black;
|
||||
padding: 0px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.example {
|
||||
background-color: #fefeee;
|
||||
}
|
||||
.presets strong {
|
||||
display: inline-block;
|
||||
width: 75px;
|
||||
}
|
||||
.presets {
|
||||
margin-bottom: -6px;
|
||||
max-width: 60%;
|
||||
}
|
||||
.presets input {
|
||||
margin: 2px 0;
|
||||
@@ -139,6 +145,9 @@ label.wide,
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
}
|
||||
.desc .btn {
|
||||
font-style: normal;
|
||||
}
|
||||
.desc.narrow {
|
||||
margin: 0 0 0 200px!important;
|
||||
}
|
||||
@@ -156,6 +165,9 @@ input[type="checkbox"]+.desc {
|
||||
color: #666;
|
||||
margin: 1em 0;
|
||||
}
|
||||
.col2 p {
|
||||
margin-left: 3px;
|
||||
}
|
||||
.field-pair {
|
||||
padding: 6px;
|
||||
clear: both;
|
||||
@@ -169,8 +181,8 @@ input[type="checkbox"]+.desc {
|
||||
background-color: #F8F8F8;
|
||||
}
|
||||
.field-pair:last-child,
|
||||
.no-field-pair-bg {
|
||||
background-color: transparent;
|
||||
.field-pair.no-field-pair-bg {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
.alt,
|
||||
.infoTableSeperator.alt {
|
||||
@@ -217,10 +229,38 @@ input[type='checkbox'] {
|
||||
padding: 0;
|
||||
margin-left: 5px;
|
||||
}
|
||||
textarea:hover, input[type="date"]:hover, input[type="datetime"]:hover, input[type="datetime-local"]:hover, input[type="email"]:hover, input[type="month"]:hover, input[type="number"]:hover, input[type="password"]:hover, input[type="search"]:hover, input[type="tel"]:hover, input[type="text"]:hover, input[type="time"]:hover, input[type="url"]:hover, input[type="week"]:hover, textarea:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="email"]:focus, input[type="month"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="time"]:focus, input[type="url"]:focus, input[type="week"]:focus {
|
||||
textarea:hover,
|
||||
input[type="date"]:hover,
|
||||
input[type="datetime"]:hover,
|
||||
input[type="datetime-local"]:hover,
|
||||
input[type="email"]:hover,
|
||||
input[type="month"]:hover,
|
||||
input[type="number"]:hover,
|
||||
input[type="password"]:hover,
|
||||
input[type="search"]:hover,
|
||||
input[type="tel"]:hover,
|
||||
input[type="text"]:hover,
|
||||
input[type="time"]:hover,
|
||||
input[type="url"]:hover,
|
||||
input[type="week"]:hover,
|
||||
textarea:focus,
|
||||
input[type="date"]:focus,
|
||||
input[type="datetime"]:focus,
|
||||
input[type="datetime-local"]:focus,
|
||||
input[type="email"]:focus,
|
||||
input[type="month"]:focus,
|
||||
input[type="number"]:focus,
|
||||
input[type="password"]:focus,
|
||||
input[type="search"]:focus,
|
||||
input[type="tel"]:focus,
|
||||
input[type="text"]:focus,
|
||||
input[type="time"]:focus,
|
||||
input[type="url"]:focus,
|
||||
input[type="week"]:focus {
|
||||
background-color: #fffff0;
|
||||
border: 1px solid #aaa;
|
||||
}
|
||||
|
||||
.col1 input[type='checkbox'] {
|
||||
position: absolute;
|
||||
top: auto!important;
|
||||
@@ -323,6 +363,49 @@ tr.separator {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.Sorting .explain-pattern {
|
||||
border: none;
|
||||
width: 100%;
|
||||
}
|
||||
.Sorting .pattern-table {
|
||||
border:1px solid #ccc;
|
||||
}
|
||||
.Sorting .sorter-switch {
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
.Sorting .sorter-switch-container {
|
||||
margin: 10px 0px;
|
||||
height: 1.5em;
|
||||
display: block;
|
||||
}
|
||||
.Sorting .sorter-placeholder {
|
||||
position: relative;
|
||||
}
|
||||
.Sorting .sorter-placeholder:after {
|
||||
content: "\e034";
|
||||
font-family: "Glyphicons Halflings";
|
||||
background: unset;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 30px;
|
||||
border-radius: 15px;
|
||||
border: 1px dashed #444;
|
||||
}
|
||||
.Sorting .glyphicon-option-vertical {
|
||||
margin-top: 1.5em;
|
||||
margin-right: 0.2em;
|
||||
cursor: move;
|
||||
}
|
||||
.Sorting form:not(.sorting-row) .glyphicon-option-vertical {
|
||||
visibility: hidden;
|
||||
}
|
||||
.Sorting .sorting-quick-setup {
|
||||
padding: 1.5em 2em 3em
|
||||
}
|
||||
|
||||
.RSS .rss-section input[type="text"] {
|
||||
max-width: 180px;
|
||||
}
|
||||
@@ -418,6 +501,9 @@ tr.separator {
|
||||
.align-center {
|
||||
text-align: center;
|
||||
}
|
||||
.valign-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
.nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -550,26 +636,31 @@ tr.separator {
|
||||
padding-right: 13px;
|
||||
}
|
||||
/* -- */
|
||||
.RSS .addRssTable,
|
||||
.RSS .addRssTable input[type="text"] {
|
||||
width: 100%;
|
||||
}
|
||||
.RSS .addRssTable .new-feed-title {
|
||||
max-width: 250px;
|
||||
}
|
||||
.RSS .addRssTable .new-feed-url {
|
||||
width: 70%;
|
||||
}
|
||||
h2.activeRSS {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.activeRSS a, .activeRSS a:visited {
|
||||
text-decoration: none;
|
||||
.activeRSS a,
|
||||
.activeRSS a:visited {
|
||||
color: #000;
|
||||
}
|
||||
.activeRSS a:hover {
|
||||
color: #4b4742;
|
||||
}
|
||||
.activeRSS a:first-of-type {
|
||||
text-decoration: underline!important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
.favicon {
|
||||
background-position: center center!important;
|
||||
background-size: 16px 16px;
|
||||
background-position: center center !important;
|
||||
background-size: 22px 22px;
|
||||
opacity: 1;
|
||||
top: -1px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
float: left;
|
||||
margin: 0 6px 0 2px;
|
||||
text-align: center;
|
||||
@@ -589,6 +680,7 @@ h2.activeRSS {
|
||||
}
|
||||
#subscriptions {
|
||||
border: 1px solid #E5E5E5;
|
||||
width: 100%;
|
||||
}
|
||||
.data-row {
|
||||
border-top: 1px solid #E5E5E5;
|
||||
@@ -600,6 +692,7 @@ h2.activeRSS {
|
||||
#subscriptions .chk {
|
||||
padding: 8px 5px 5px;
|
||||
vertical-align: middle;
|
||||
width: 40px;
|
||||
}
|
||||
#subscriptions .title {
|
||||
font-weight: bold;
|
||||
@@ -607,10 +700,11 @@ h2.activeRSS {
|
||||
width: auto;
|
||||
}
|
||||
#subscriptions .favicon {
|
||||
margin-left: 8px;
|
||||
margin-left: 7px;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.ie6 .subscription-title {
|
||||
width: 20em;
|
||||
#subscriptions .glyphicon {
|
||||
margin-top: 3px;
|
||||
}
|
||||
.subscription-title,
|
||||
.subscription-title:hover {
|
||||
@@ -716,41 +810,6 @@ ul.tabs li.active a {
|
||||
.checkbox-days label {
|
||||
padding: 2px 20px;
|
||||
}
|
||||
.rating-filter {
|
||||
float: left;
|
||||
}
|
||||
.rating-filter p {
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
.rating-filter select {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.rating-filter input {
|
||||
vertical-align: middle;
|
||||
margin-top: -1px;
|
||||
}
|
||||
.rating-filter label {
|
||||
display: inline-block;
|
||||
padding-left: 0px;
|
||||
width: 100px;
|
||||
}
|
||||
.rating-filter input[type="checkbox"] {
|
||||
display: inline;
|
||||
}
|
||||
.rating-filter input[type="checkbox"] + label {
|
||||
padding-left: 20px;
|
||||
padding-top: 5px;
|
||||
width: auto;
|
||||
}
|
||||
.rating-filter p > span:first-child {
|
||||
float: left;
|
||||
width: 130px;
|
||||
}
|
||||
.rating-filter .desc {
|
||||
display: block;
|
||||
margin: 0px;
|
||||
padding-left: 103px;
|
||||
}
|
||||
|
||||
/** EDITS 2015 **/
|
||||
* {
|
||||
@@ -795,6 +854,7 @@ input[type="submit"]:hover {
|
||||
input[type="text"],
|
||||
input[type="email"],
|
||||
input[type="url"],
|
||||
input[type="date"],
|
||||
input[type="number"],
|
||||
input[type="password"],
|
||||
textarea,
|
||||
@@ -807,6 +867,7 @@ select {
|
||||
vertical-align:middle;
|
||||
max-width: 100%;
|
||||
min-height: 34px;
|
||||
min-width: 55px;
|
||||
font-size: 13px;
|
||||
background-color: white;
|
||||
}
|
||||
@@ -953,7 +1014,7 @@ input[type="checkbox"] {
|
||||
}
|
||||
*/
|
||||
.navbar-default .navbar-nav>li>a {
|
||||
color: black !important;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-nav>li>a:hover,
|
||||
@@ -990,6 +1051,32 @@ input[type="checkbox"] {
|
||||
margin: 10px 0px;
|
||||
}
|
||||
|
||||
.Servers .server-frame {
|
||||
position: relative;
|
||||
width: 220px;
|
||||
height: 325px;
|
||||
margin-bottom: -325px;
|
||||
left: -240px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.Servers .server-frame a {
|
||||
color: black !important;
|
||||
text-decoration: none !important;
|
||||
opacity: 0.8;
|
||||
font-size: 2em;
|
||||
font-family: arial, sans-serif !important;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: -5px;
|
||||
}
|
||||
|
||||
.Servers .server-frame iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.Servers .col2 .label {
|
||||
margin-top: 8px;
|
||||
font-size: 0.85em;
|
||||
@@ -1094,6 +1181,10 @@ input[type="checkbox"] {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.host-warning-highlight {
|
||||
border-color: #F0AD4E !important;
|
||||
}
|
||||
|
||||
.fileBrowser .glyphicon {
|
||||
margin-right: 2px;
|
||||
top: 1px;
|
||||
@@ -1135,7 +1226,6 @@ input[type="checkbox"] {
|
||||
}
|
||||
.value-and-select select {
|
||||
min-width: 30px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.dotOne, .dotTwo, .dotThree {
|
||||
@@ -1172,6 +1262,31 @@ input[type="checkbox"] {
|
||||
100% { transform: rotate(359deg); }
|
||||
}
|
||||
|
||||
/***
|
||||
RTL Fixes
|
||||
***/
|
||||
html[dir="rtl"] .col1 input[type='checkbox'],
|
||||
html[dir="rtl"] .col2 h3 a {
|
||||
left: 5px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .modal-header .close {
|
||||
float: left;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .field-pair {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .Sorting .presets.float-left,
|
||||
html[dir="rtl"] .checkbox-days {
|
||||
float: none;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .Scheduling form[action="addSchedule"] input[type="checkbox"] {
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1200px) {
|
||||
.Categories input[name="dir"] {
|
||||
max-width: 240px !important;
|
||||
@@ -1242,6 +1357,12 @@ input[type="checkbox"] {
|
||||
padding: 0px 15px 10px;
|
||||
width: inherit;
|
||||
}
|
||||
.Sorting .glyphicon-option-vertical {
|
||||
display: none;
|
||||
}
|
||||
.Sorting .sorter h3 {
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
|
||||
@@ -1,111 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 608 608"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
stroke-linejoin="round"
|
||||
stroke-miterlimit="1.414"
|
||||
version="1.1"
|
||||
id="svg12"
|
||||
sodipodi:docname="logo-small.svg"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
|
||||
<metadata
|
||||
id="metadata18">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs16" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1530"
|
||||
inkscape:window-height="836"
|
||||
id="namedview14"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.0978763"
|
||||
inkscape:cx="244.1731"
|
||||
inkscape:cy="331.66596"
|
||||
inkscape:window-x="70"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg12" />
|
||||
<path
|
||||
d="M630.988 320.63V188.324h99.863v-35.62l110.197 101.773L730.85 356.25v-35.62h-99.86z"
|
||||
fill="none"
|
||||
stroke-width="16.62"
|
||||
stroke="#000"
|
||||
transform="matrix(0 2.665 -2.7482 0 1003.016 -1657.67)"
|
||||
id="path2" />
|
||||
<path
|
||||
d="M121.86 23.913h363.604v266.135h97.89l-279.69 293.667L23.97 290.048h97.89V23.913z"
|
||||
fill="#FFB300"
|
||||
id="path4" />
|
||||
<path
|
||||
d="M303.664 583.797L122.274 23.975h362.78l-181.39 559.822z"
|
||||
fill="#FFCA28"
|
||||
id="path6" />
|
||||
<path
|
||||
d="M200.157 512.87H50.46v-31.503h88.824v-27.95H50.46v-90.48h149.697V394.2h-88.823v27.95h88.823v90.718zm88.823-31.503h27.95v-27.95h-27.95v27.95zm88.824 31.503H228.107v-90.718h88.823v-27.95h-88.823v-31.266h149.697V512.87zm88.823-31.503h27.95v-87.165h-27.95v87.165zm-60.874 31.503V303.72h60.874v59.216h88.823V512.87H405.753z"
|
||||
fill="none"
|
||||
stroke-width="45.004"
|
||||
stroke-linecap="round"
|
||||
stroke="#000"
|
||||
id="path8" />
|
||||
<path
|
||||
d="M200.157 512.87H50.46v-31.503h88.824v-27.95H50.46v-90.48h149.697V394.2h-88.823v27.95h88.823v90.718zm88.823-31.503h27.95v-27.95h-27.95v27.95zm88.824 31.503H228.107v-90.718h88.823v-27.95h-88.823v-31.266h149.697V512.87zm88.823-31.503h27.95v-87.165h-27.95v87.165zm-60.874 31.503V303.72h60.874v59.216h88.823V512.87H405.753z"
|
||||
fill="#fff"
|
||||
fill-rule="nonzero"
|
||||
id="path10" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:322.60137939px;line-height:52.04999924;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffb300;fill-opacity:1;stroke:none;stroke-width:10.99777317"
|
||||
x="193.43372"
|
||||
y="285.7019"
|
||||
id="text830"
|
||||
transform="scale(1.022657,0.97784496)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan828"
|
||||
x="193.43372"
|
||||
y="285.7019"
|
||||
style="font-weight:bold;fill:#ffb300;fill-opacity:1;stroke-width:10.99777317">3</tspan></text>
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot832"
|
||||
style="fill:black;fill-opacity:1;stroke:none;font-family:sans-serif;font-style:normal;font-weight:normal;font-size:29.33333333px;line-height:52.05;letter-spacing:0px;word-spacing:0px"><flowRegion
|
||||
id="flowRegion834"><rect
|
||||
id="rect836"
|
||||
width="181.6174"
|
||||
height="223.85559"
|
||||
x="224.13559"
|
||||
y="79.86441" /></flowRegion><flowPara
|
||||
id="flowPara838" /></flowRoot> <flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot840"
|
||||
style="fill:black;fill-opacity:1;stroke:none;font-family:sans-serif;font-style:normal;font-weight:normal;font-size:29.33333333px;line-height:52.05;letter-spacing:0px;word-spacing:0px"><flowRegion
|
||||
id="flowRegion842"><rect
|
||||
id="rect844"
|
||||
width="7.7288136"
|
||||
height="30.915255"
|
||||
x="293.69492"
|
||||
y="283.38983" /></flowRegion><flowPara
|
||||
id="flowPara846" /></flowRoot></svg>
|
||||
<svg viewBox="0 0 608 608" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M630.988 320.63V188.324h99.863v-35.62l110.197 101.773L730.85 356.25v-35.62h-99.86z" fill="none" stroke-width="16.62" stroke="#000" transform="matrix(0 2.665 -2.7482 0 1003.016 -1657.67)"/><path d="M121.86 23.913h363.604v266.135h97.89l-279.69 293.667L23.97 290.048h97.89V23.913z" fill="#FFB300"/><path d="M303.664 583.797L122.274 23.975h362.78l-181.39 559.822z" fill="#FFCA28"/><path d="M200.157 512.87H50.46v-31.503h88.824v-27.95H50.46v-90.48h149.697V394.2h-88.823v27.95h88.823v90.718zm88.823-31.503h27.95v-27.95h-27.95v27.95zm88.824 31.503H228.107v-90.718h88.823v-27.95h-88.823v-31.266h149.697V512.87zm88.823-31.503h27.95v-87.165h-27.95v87.165zm-60.874 31.503V303.72h60.874v59.216h88.823V512.87H405.753z" fill="none" stroke-width="45.004" stroke-linecap="round" stroke="#000"/><path d="M200.157 512.87H50.46v-31.503h88.824v-27.95H50.46v-90.48h149.697V394.2h-88.823v27.95h88.823v90.718zm88.823-31.503h27.95v-27.95h-27.95v27.95zm88.824 31.503H228.107v-90.718h88.823v-27.95h-88.823v-31.266h149.697V512.87zm88.823-31.503h27.95v-87.165h-27.95v87.165zm-60.874 31.503V303.72h60.874v59.216h88.823V512.87H405.753z" fill="#fff" fill-rule="nonzero"/></svg>
|
||||
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 1.3 KiB |
File diff suppressed because one or more lines are too long
2
interfaces/Config/templates/staticcfg/js/jquery-3.5.1.min.js
vendored
Normal file
2
interfaces/Config/templates/staticcfg/js/jquery-3.5.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -60,6 +60,7 @@
|
||||
// Initialize
|
||||
this.element = $(element);
|
||||
this.initialDir = null;
|
||||
this.showFiles = false;
|
||||
this.currentBrowserPath = null;
|
||||
this.currentRequest = null;
|
||||
this.fileBrowserDialog = $('#filebrowser_modal .modal-body');
|
||||
@@ -99,6 +100,11 @@
|
||||
this.initialDir = this.element.data('initialdir') + folderSeperator + this.element.val();
|
||||
}
|
||||
|
||||
// Are we selecting files or folders
|
||||
if(this.element.data('files')) {
|
||||
this.showFiles = true
|
||||
}
|
||||
|
||||
// Browse
|
||||
this.browse(this.initialDir , folderBrowseUrl);
|
||||
|
||||
@@ -109,13 +115,13 @@
|
||||
// Remove start
|
||||
self.currentBrowserPath = self.currentBrowserPath.replace(self.element.data('initialdir')+folderSeperator, '');
|
||||
// If it's identical to the initial dir the replacement won't work
|
||||
if(self.currentBrowserPath == self.element.data('initialdir')) {
|
||||
if(self.currentBrowserPath === self.element.data('initialdir')) {
|
||||
self.currentBrowserPath = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Changed?
|
||||
if(self.element.val() != self.currentBrowserPath) {
|
||||
if(self.element.val() !== self.currentBrowserPath) {
|
||||
self.element.val(self.currentBrowserPath);
|
||||
formHasChanged = true;
|
||||
}
|
||||
@@ -144,12 +150,20 @@
|
||||
// Still loading
|
||||
if (this.currentRequest) this.currentRequest.abort();
|
||||
|
||||
// Show hidden folders on Linux?
|
||||
var extraHidden = $('#show_hidden_folders').is(':checked') ? '&show_hidden_folders=1' : '';
|
||||
// Show hidden folders
|
||||
var params = { name: path}
|
||||
if($('#show_hidden_folders').is(':checked')) {
|
||||
params['show_hidden_folders'] = "1"
|
||||
}
|
||||
|
||||
// Show files?
|
||||
if(this.showFiles) {
|
||||
params['show_files'] = "1"
|
||||
}
|
||||
|
||||
// Get current folders
|
||||
this.currentBrowserPath = path;
|
||||
this.currentRequest = $.getJSON(endpoint + extraHidden, { name: path }, function (data) {
|
||||
this.currentRequest = $.getJSON(endpoint, params, function (data) {
|
||||
// Clean
|
||||
self.fileBrowserDialog.empty();
|
||||
|
||||
@@ -157,17 +171,27 @@
|
||||
var list = $('<div class="list-group">').appendTo(self.fileBrowserDialog);
|
||||
$.each(data.paths, function (i, entry) {
|
||||
// Title for first one
|
||||
if(i == 0) {
|
||||
if(i === 0) {
|
||||
self.fileBrowserDialog.prepend($('<h4>').text(entry.current_path))
|
||||
return
|
||||
}
|
||||
// Regular link
|
||||
link = $('<a class="list-group-item" href="javascript:void(0)" />').click(function () {
|
||||
self.browse(entry.path, endpoint); }
|
||||
).text(entry.name);
|
||||
// Are we looking for files and did we select a file?
|
||||
if(self.showFiles && !entry.dir) {
|
||||
// Trigger selection
|
||||
self.currentBrowserPath = entry.path
|
||||
$('#filebrowser_modal_accept').click()
|
||||
} else {
|
||||
self.browse(entry.path, endpoint);
|
||||
}
|
||||
}).text(entry.name);
|
||||
|
||||
// Back image
|
||||
if(entry.name == '..') {
|
||||
if(entry.name === '..') {
|
||||
$('<span class="glyphicon glyphicon-arrow-left"></span> ').prependTo(link);
|
||||
} else if(!entry.dir) {
|
||||
$('<span class="glyphicon glyphicon-file"></span> ').prependTo(link);
|
||||
} else {
|
||||
$('<span class="glyphicon glyphicon-folder-open"></span> ').prependTo(link);
|
||||
}
|
||||
@@ -203,7 +227,12 @@ $.fn.extractFormDataTo = function(target) {
|
||||
var selects = $("select", this);
|
||||
|
||||
selects.each(function (i,elem) {
|
||||
target[elem.name] = elem.value;
|
||||
if (elem.selectedOptions.length > 1) {
|
||||
// Handle <select multiple="multiple">
|
||||
target[elem.name] = Array.from(elem.selectedOptions).map(({ value }) => value).toString();
|
||||
} else {
|
||||
target[elem.name] = elem.value;
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
@@ -215,7 +244,7 @@ $.fn.extractFormDataTo = function(target) {
|
||||
* (c) 2015 SABnzbd Team, Inc. All rights reserved.
|
||||
*/
|
||||
function config_success() {
|
||||
$('.saveButton').each(function () {
|
||||
$('.saveButton[disabled=disabled]').each(function () {
|
||||
$(this).removeAttr("disabled").html('<span class="glyphicon glyphicon-ok"></span> '+configTranslate.saveChanges);
|
||||
});
|
||||
// Let us leave!
|
||||
@@ -223,7 +252,7 @@ function config_success() {
|
||||
formHasChanged = false;
|
||||
}
|
||||
function config_failure() {
|
||||
$('.saveButton').each(function () {
|
||||
$('.saveButton[disabled=disabled]').each(function () {
|
||||
$(this).removeAttr("disabled").addClass('btn-danger').html('<span class="glyphicon glyphicon-remove"></span> '+configTranslate.failed);
|
||||
});
|
||||
// Can't go yet..
|
||||
@@ -233,8 +262,9 @@ function do_restart() {
|
||||
// Show overlay
|
||||
$('.main-restarting').show()
|
||||
|
||||
// What template
|
||||
var switchedHTTPS = ($('#enable_https').is(':checked') == ($('#enable_https').data('original') === undefined))
|
||||
// Check if we need redirect
|
||||
// Uses == on purpose, because val() returns string and data() returns int!
|
||||
var switchedHTTPS = ($('#enable_https').is(':checked') === ($('#enable_https').data('original') === undefined))
|
||||
var portsUnchanged = ($('#port').val() == $('#port').data('original')) && ($('#https_port').val() == $('#https_port').data('original'))
|
||||
|
||||
// Are we on settings page or did nothing change?
|
||||
@@ -243,7 +273,7 @@ function do_restart() {
|
||||
var urlTotal = window.location.origin + urlBase
|
||||
} else {
|
||||
// Protocol and port depend on http(s) setting
|
||||
if($('#enable_https').is(':checked') && (window.location.protocol == 'https:' || !$('#https_port').val())) {
|
||||
if($('#enable_https').is(':checked') && (window.location.protocol === 'https:' || !$('#https_port').val())) {
|
||||
// Https on and we visited this page from HTTPS
|
||||
var urlProtocol = 'https:';
|
||||
var urlPort = $('#https_port').val() ? $('#https_port').val() : $('#port').val();
|
||||
@@ -261,16 +291,16 @@ function do_restart() {
|
||||
$('.main-restarting .restarting-url').text(urlTotal)
|
||||
|
||||
// Initiate restart
|
||||
$.ajax({ url: '../../config/restart?apikey=' + sabSession,
|
||||
$.ajax({ url: '../../api?mode=restart&apikey=' + sabSession,
|
||||
complete: function() {
|
||||
// Keep counter of failures
|
||||
var failureCounter = 0;
|
||||
var loopCounter = 0;
|
||||
|
||||
// Now we try until we can connect
|
||||
var refreshInterval = setInterval(function() {
|
||||
// We skip the first one
|
||||
if(failureCounter == 0) {
|
||||
failureCounter = failureCounter+1;
|
||||
setInterval(function() {
|
||||
loopCounter = loopCounter+1;
|
||||
// We skip the first one so we give it time to shutdown
|
||||
if(loopCounter < 2) {
|
||||
return
|
||||
}
|
||||
$.ajax({ url: urlTotal,
|
||||
@@ -279,21 +309,20 @@ function do_restart() {
|
||||
location.href = urlTotal;
|
||||
},
|
||||
error: function(status, text) {
|
||||
failureCounter = failureCounter+1;
|
||||
// Too many failuers and we give up
|
||||
if(failureCounter >= 6) {
|
||||
// Too many failures and we give up
|
||||
if(loopCounter >= 10) {
|
||||
// If the port has changed 'Access-Control-Allow-Origin' header will not allow
|
||||
// us to check if the server is back up. So after 7 failures we redirect
|
||||
// us to check if the server is back up. So after 10 failures (20 sec) we redirect
|
||||
// anyway in the hopes it works anyway..
|
||||
location.href = urlTotal;
|
||||
}
|
||||
}
|
||||
})
|
||||
}, 4000)
|
||||
}, 2000)
|
||||
|
||||
// Exception if we go from HTTPS to HTTP
|
||||
// (this is not allowed by browsers and all of the above will be ignored)
|
||||
if(window.location.protocol != urlProtocol) {
|
||||
if(window.location.protocol !== urlProtocol) {
|
||||
// Saftey redirect after 20 sec
|
||||
setTimeout(function() {
|
||||
location.href = urlTotal;
|
||||
@@ -303,7 +332,7 @@ function do_restart() {
|
||||
});
|
||||
}
|
||||
|
||||
// Remove obfusication
|
||||
// Remove obfuscation
|
||||
function removeObfuscation() {
|
||||
$('input[data-hide]').each(function(index, objInput) {
|
||||
$(objInput).attr('name', $(objInput).data('hide'))
|
||||
@@ -319,6 +348,36 @@ function addRowColor() {
|
||||
})
|
||||
}
|
||||
|
||||
// Set default functions for the autocomplete everywhere
|
||||
jQuery.extend(jQuery.fn.typeahead.defaults, {
|
||||
source: function (query, process) {
|
||||
// If there's no separator, it must be a relative path
|
||||
if(query.split(folderSeperator).length < 2 && this.$element.data('initialdir')) {
|
||||
query = this.$element.data('initialdir') + folderSeperator + query;
|
||||
}
|
||||
var params = { compact: "1", name: query }
|
||||
if($('#show_hidden_folders').is(':checked')) {
|
||||
params['show_hidden_folders'] = "1"
|
||||
}
|
||||
if(this.$element.data('files')) {
|
||||
params['show_files'] = "1"
|
||||
}
|
||||
// Get info from the API
|
||||
return jQuery.get(folderBrowseUrl, params, function (data) {
|
||||
return process(data["paths"]);
|
||||
});
|
||||
},
|
||||
updater: function(item) {
|
||||
// Is it a relative path?
|
||||
if(item.indexOf(this.$element.data('initialdir')) === 0) {
|
||||
// Remove start
|
||||
return item.replace(this.$element.data('initialdir') + folderSeperator, '');
|
||||
}
|
||||
// Full path
|
||||
return item
|
||||
}
|
||||
})
|
||||
|
||||
$(document).ready(function () {
|
||||
/**
|
||||
Restart function
|
||||
@@ -346,8 +405,9 @@ $(document).ready(function () {
|
||||
datatype: 'json',
|
||||
// But first remove Obfuscation!
|
||||
beforeSerialize: removeObfuscation,
|
||||
beforeSubmit: function () {
|
||||
$('.saveButton').each(function () {
|
||||
beforeSubmit: function (arr, form, options) {
|
||||
// Only in the current form
|
||||
form.find('.saveButton').each(function () {
|
||||
$(this).attr("disabled", "disabled").removeClass('btn-danger').html('<span class="glyphicon glyphicon-transfer"></span> ' + configTranslate.saving);
|
||||
});
|
||||
},
|
||||
@@ -408,7 +468,7 @@ $(document).ready(function () {
|
||||
$('input[type="checkbox"]').parents('label').addClass('config-hover')
|
||||
|
||||
// Disable sections
|
||||
var checkDisabled = '#rating_enable, #enable_tv_sorting, #enable_movie_sorting, #enable_date_sorting'
|
||||
var checkDisabled = '#enable_tv_sorting, #enable_movie_sorting, #enable_date_sorting'
|
||||
|
||||
$(checkDisabled).on('change', function() {
|
||||
$(this).parent().nextAll().toggleClass('disabled')
|
||||
@@ -424,12 +484,15 @@ $(document).ready(function () {
|
||||
$('.advanced-settings').toggle()
|
||||
addRowColor()
|
||||
})
|
||||
if(localStorage.getItem('advanced-settings') == 'true') {
|
||||
if(localStorage.getItem('advanced-settings') === 'true') {
|
||||
$('.advanced-settings').show()
|
||||
$('#advanced-settings-button').prop('checked', true)
|
||||
addRowColor()
|
||||
}
|
||||
addRowColor()
|
||||
|
||||
// Add tooltips
|
||||
jQuery('[title]').tooltip()
|
||||
});
|
||||
|
||||
/*
|
||||
|
||||
@@ -9,7 +9,7 @@ BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE B
|
||||
|
||||
1. Definitions
|
||||
|
||||
1. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License.
|
||||
1. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("syncing") will be considered an Adaptation for the purpose of this License.
|
||||
2. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License.
|
||||
3. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership.
|
||||
4. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License.
|
||||
@@ -44,7 +44,7 @@ The above rights may be exercised in all media and formats whether now known or
|
||||
|
||||
5. Representations, Warranties and Disclaimer
|
||||
|
||||
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
|
||||
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
|
||||
|
||||
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,17 +1,33 @@
|
||||
<div class="history" id="history-tab" data-bind="visible: hasHistory() || displayTabbed()" style="display: none">
|
||||
<h2>$T('menu-history')</h2>
|
||||
<div class="history" id="history-tab">
|
||||
<div class="history-header">
|
||||
<h2>$T('menu-history') <small data-bind="visible: history.showArchive()">($T('archive'))</small></h2>
|
||||
<a href="#" data-bind="click: history.showMultiEdit, visible: hasHistory()">
|
||||
<span class="glyphicon glyphicon-tasks" data-tooltip="true" data-placement="left" title="$T('Glitter-multiOperations')"></span>
|
||||
</a>
|
||||
</div>
|
||||
<table class="table table-hover history-table paginated">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 25px;"></th>
|
||||
<th></th>
|
||||
<th class="table-status-header" data-bind="css: { 'table-header-status-smaller' : extraHistoryColumn }"></th>
|
||||
<th class="table-header-extra" data-bind="css: { 'table-extra-header-visible' : extraHistoryColumn }"></th>
|
||||
<th class="table-status-header" data-bind="css: { 'table-header-status-smaller' : extraHistoryColumns().length }"></th>
|
||||
<!-- ko foreach: extraHistoryColumns -->
|
||||
<th class="table-header-extra"></th>
|
||||
<!-- /ko -->
|
||||
<th style="width: 130px;"></th>
|
||||
<th style="width: 60px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-bind="foreach: history.historyItems">
|
||||
<!-- ko if: !hasHistory() -->
|
||||
<tbody class="no-downloads">
|
||||
<tr>
|
||||
<td colspan="6" data-bind="attr: { 'colspan': 5 + extraHistoryColumns().length }">
|
||||
<span>$T('empty')</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<!-- /ko -->
|
||||
<tbody data-bind="foreach: history.historyItems, visible: hasHistory()" style="display: none;">
|
||||
<tr class="history-item" data-bind="css: {'history-failed-download':failed()}">
|
||||
<td>
|
||||
<div data-bind="visible: processingWaiting()">
|
||||
@@ -39,111 +55,24 @@
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="name" data-bind="css: { 'name-has-ratings' : historyStatus.has_rating }">
|
||||
<td class="name">
|
||||
<div class="row-wrap-text">
|
||||
<a class="retry-buttontext" href="#" data-bind="visible: (failed() && canRetry()), click: retry">$T('button-retry')</a>
|
||||
<span data-bind="text: historyStatus.name, attr: { 'title': historyStatus.name() }"></span>
|
||||
</div>
|
||||
|
||||
<!-- ko if: historyStatus.has_rating -->
|
||||
<div class="dropdown history-ratings">
|
||||
<a href="#" class="name-icons hover-button" data-toggle="dropdown" onclick="keepOpen(this)">
|
||||
<span class="glyphicon glyphicon-thumbs-up"></span> <span data-bind="text: historyStatus.rating_avg_vote_up"></span>
|
||||
<span class="glyphicon glyphicon-thumbs-down"></span> <span data-bind="text: historyStatus.rating_avg_vote_down"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu history-ratings-menu">
|
||||
<li>
|
||||
<form class="history-ratings-basic">
|
||||
<label>
|
||||
<input type="radio" value="up" data-bind="attr: { 'name': 'ratings-status-'+nzo_id, 'checked': historyStatus.rating_user_vote() == 1 }, event: { change: setUserVote }" />
|
||||
<span class="glyphicon glyphicon-thumbs-up"></span>
|
||||
<span data-bind="text: historyStatus.rating_avg_vote_up"></span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" value="down" data-bind="attr: { 'name': 'ratings-status-'+nzo_id, 'checked': historyStatus.rating_user_vote() == 2 }, event: { change: setUserVote }" />
|
||||
<span class="glyphicon glyphicon-thumbs-down"></span>
|
||||
<span data-bind="text: historyStatus.rating_avg_vote_down"></span>
|
||||
</label>
|
||||
<label>
|
||||
<span class="glyphicon glyphicon-facetime-video"></span>
|
||||
<select name="ratings-video" data-bind="value: historyStatus.rating_user_video, event: { change: setUserRating }, disable: historyStatus.rating_user_video">
|
||||
<option value=""> </option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="7">7</option>
|
||||
<option value="8">8</option>
|
||||
<option value="9">9</option>
|
||||
<option value="10">10</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span class="glyphicon glyphicon-volume-up"></span>
|
||||
<select name="ratings-audio" data-bind="value: historyStatus.rating_user_audio, event: { change: setUserRating }, disable: historyStatus.rating_user_audio">
|
||||
<option value=""> </option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="7">7</option>
|
||||
<option value="8">8</option>
|
||||
<option value="9">9</option>
|
||||
<option value="10">10</option>
|
||||
</select>
|
||||
</label>
|
||||
<!-- ko if: historyStatus.url_info -->
|
||||
<a href="#" target="_blank" data-bind="attr: { 'href':historyStatus.url_info }" title="$T('Glitter-openInfoURL')"><span class="glyphicon glyphicon-globe"></span></a>
|
||||
<!-- /ko -->
|
||||
</form>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<form class="history-ratings-report" data-bind="submit: setUserReport">
|
||||
<strong>$T('report')</strong>
|
||||
<br />
|
||||
<label>
|
||||
<input type="radio" name="rating_flag" value="spam" /> $T('spam')
|
||||
</label>
|
||||
<br />
|
||||
<label>
|
||||
<input type="radio" name="rating_flag" value="encrypted" /> $T('encrypted')
|
||||
</label>
|
||||
<br />
|
||||
<label>
|
||||
<input type="radio" name="rating_flag" value="expired" /> $T('expired')
|
||||
<select name="ratings-report-expired-server" class="ratings-report-hidden form-control" data-bind="options: \$parent.servers, optionsText: 'host', optionsValue: 'host', optionsCaption: '$T('nzo-all')'"></select>
|
||||
</label>
|
||||
<br />
|
||||
<label>
|
||||
<input type="radio" name="rating_flag" value="other" /> $T('otherProblem')
|
||||
<input type="text" class="form-control ratings-report-hidden" name="ratings-report-other" />
|
||||
</label>
|
||||
<br />
|
||||
<label>
|
||||
<input type="radio" name="rating_flag" value="comment" /> $T('comment')
|
||||
<input type="text" class="form-control ratings-report-hidden" name="ratings-report-comment" />
|
||||
</label>
|
||||
<br />
|
||||
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-ok"></span> $T('send')</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
</td>
|
||||
<td class="status row-wrap-text" data-bind="text: statusText()" onclick="showDetails(this)"></td>
|
||||
<!-- ko foreach: parent.parent.extraHistoryColumns -->
|
||||
<td class="row-extra-text" onclick="showDetails(this)">
|
||||
<div class="row-wrap-text" data-bind="text: extraText">
|
||||
</div>
|
||||
<div class="row-wrap-text" data-bind="text: \$parent.showColumn(\$data)"></div>
|
||||
</td>
|
||||
<!-- /ko -->
|
||||
<td class="history-completedon row-wrap-text" data-bind="text: completedOn(), attr: { 'data-timestamp': completed }" onclick="showDetails(this)"></td>
|
||||
<td class="delete">
|
||||
<div class="dropdown">
|
||||
<label data-bind="visible: parent.isMultiEditing()">
|
||||
<input type="checkbox" name="multiedit" title="$T('Glitter-multiSelect')" data-bind="click: parent.addMultiEdit, attr: { 'id': 'multiedit_' + id } " />
|
||||
</label>
|
||||
<div class="dropdown" data-bind="visible: !parent.isMultiEditing()">
|
||||
<a href="#" data-toggle="dropdown" data-bind="click: updateAllHistoryInfo">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
@@ -154,13 +83,20 @@
|
||||
<div class="col-sm-2">$T('name')</div>
|
||||
<div class="col-sm-10" data-bind="text: historyStatus.name"></div>
|
||||
</div>
|
||||
<div class="row" data-bind="visible: historyStatus.time_added">
|
||||
<div class="col-sm-2">$T('rss-added')</div>
|
||||
<div class="col-sm-10" data-bind="text: timeAdded(), attr: { 'data-timestamp': historyStatus.time_added }"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-2">$T('post-Completed')</div>
|
||||
<div class="col-sm-10" data-bind="text: completedOn, attr: { 'data-timestamp': completed }"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-2">$T('status')</div>
|
||||
<div class="col-sm-10" data-bind="text: glitterTranslate.status[historyStatus.status()] ? glitterTranslate.status[historyStatus.status()] : statusText()"></div>
|
||||
<div class="col-sm-10">
|
||||
<span data-bind="text: glitterTranslate.status[historyStatus.status()] ? glitterTranslate.status[historyStatus.status()] : statusText()"></span>
|
||||
<a href="#" class="mark-completed-link" data-bind="visible: failed(), click: markAsCompleted" title="$T('button-mark-completed')"><span class="glyphicon glyphicon-ok"></span> $T('post-Completed')</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-2">$T('size')</div>
|
||||
@@ -174,7 +110,7 @@
|
||||
<div class="col-sm-2">$T('srv-password')</div>
|
||||
<div class="col-sm-10" data-bind="text: historyStatus.password"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="row" data-bind="visible: historyStatus.storage() || historyStatus.path()">
|
||||
<div class="col-sm-2">$T('msg-path')</div>
|
||||
<div class="col-sm-10" data-bind="text: historyStatus.storage() == '' ? historyStatus.path : historyStatus.storage"></div>
|
||||
</div>
|
||||
@@ -188,7 +124,7 @@
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
</div>
|
||||
<a href="#" data-bind="click: deleteSlot">
|
||||
<a href="#" data-bind="click: parent.triggerRemoveDownload">
|
||||
<span class="hover-button glyphicon glyphicon-trash" data-bind="css: { 'glyphicon-stop' : processingDownload() == 2, disabled : processingDownload() == 1 }, attr: { title: processingDownload() == 2 ? '$T('abort')' : '$T('nzo-delete')' }"></span>
|
||||
</a>
|
||||
</td>
|
||||
@@ -210,9 +146,24 @@
|
||||
</ul>
|
||||
|
||||
<div class="multioperations-selector" id="history-options">
|
||||
<a href="#" class="hover-button" title="$T('link-retryAll')" data-tooltip="true" data-placement="left" data-bind="click: history.retryAllFailed"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<a href="#" class="hover-button" title="$T('showAllHis') / $T('showFailedHis')" data-tooltip="true" data-placement="left" data-bind="click: history.toggleShowFailed, css: { 'history-options-show-failed': history.showFailed }"><span class="glyphicon glyphicon-exclamation-sign"></span></a>
|
||||
<a href="#modal-purge-history" class="hover-button" title="$T('purgeHist')" data-toggle="modal" data-tooltip="true" data-placement="left"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
<a href="#" class="hover-button history-archive" title="$T('showArchive') / $T('showAllHis')" data-tooltip="true" data-placement="top" data-bind="click: history.toggleShowArchive, css: { 'history-options-show-failed': history.showArchive }"><svg viewBox="6 6 36 36" height="14" width="14" class="archive-icon"><path d="M41.09 10.45l-2.77-3.36c-.56-.66-1.39-1.09-2.32-1.09h-24c-.93 0-1.76.43-2.31 1.09l-2.77 3.36c-.58.7-.92 1.58-.92 2.55v25c0 2.21 1.79 4 4 4h28c2.21 0 4-1.79 4-4v-25c0-.97-.34-1.85-.91-2.55zm-17.09 24.55l-11-11h7v-4h8v4h7l-11 11zm-13.75-25l1.63-2h24l1.87 2h-27.5z"/></svg></a>
|
||||
<a href="#" class="hover-button" title="$T('showFailedHis') / $T('showAllHis')" data-tooltip="true" data-placement="top" data-bind="click: history.toggleShowFailed, css: { 'history-options-show-failed': history.showFailed }"><span class="glyphicon glyphicon-exclamation-sign"></span></a>
|
||||
<a href="#" class="hover-button" title="$T('link-retryAll')" data-tooltip="true" data-placement="top" data-bind="click: history.retryAllFailed"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<a href="#" class="hover-button" title="$T('button-mark-completed')" data-bind="visible: (history.isMultiEditing() && hasHistory()), click: history.doMultiMarkCompleted" data-tooltip="true" data-placement="top"><span class="glyphicon glyphicon-ok"></span></a>
|
||||
|
||||
<div data-bind="visible: (history.isMultiEditing() && hasHistory())">
|
||||
<span class="label label-default" data-bind="text: history.multiEditItems().length">0</span>
|
||||
<label for="multiedit-checkall-history">
|
||||
<input type="checkbox" name="multieditCheckAll" id="multiedit-checkall-history" title="$T('Glitter-checkAll')" data-bind="click: history.checkAllJobs" data-tooltip="true" data-placement="top" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<a href="#" class="hover-button" title="$T('nzo-delete')" data-bind="visible: (history.isMultiEditing() && hasHistory()), click: history.doMultiDelete" data-tooltip="true" data-placement="top">
|
||||
<span class="glyphicon glyphicon-trash"></span>
|
||||
</a>
|
||||
<a href="#modal-purge-history" class="hover-button" title="$T('purgeHist')" data-bind="visible: !(history.isMultiEditing() && hasHistory())" data-toggle="modal" data-tooltip="true" data-placement="top">
|
||||
<span class="glyphicon glyphicon-trash"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="info-container history-info">
|
||||
@@ -221,4 +172,4 @@
|
||||
<span data-bind="text: history.downloadedMonth"></span>B $T('Glitter-thisMonth')
|
||||
<span data-bind="text: history.downloadedTotal"></span>B $T('Glitter-total')
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<button type="button" class="btn btn-default navbar-btn dropdown-toggle" data-toggle="dropdown" onclick="keepOpen(this)">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<a href="#" class="max-speed-input-clear hover-button" data-bind="click: clearSpeedLimit, visible:(speedLimit() != 100)" style="display: none;">
|
||||
<a href="#" class="max-speed-input-clear hover-button" data-bind="click: clearSpeedLimit, visible:(speedLimit() < 100 && speedLimit() > 0)" style="display: none;">
|
||||
<span class="glyphicon glyphicon-link"></span>
|
||||
</a>
|
||||
<div class="dropdown-menu max-speed-input">
|
||||
@@ -81,7 +81,7 @@
|
||||
<li data-tooltip="true" data-placement="bottom" title="SABnzbd $T('menu-config')">
|
||||
<a href="./config/"><span class="glyphicon glyphicon-cog"></span></a>
|
||||
</li>
|
||||
<li class="dropdown main-menu-link" data-bind="css: { 'active-on-queue-finish-menu': onQueueFinish()}">
|
||||
<li class="dropdown main-menu-link" data-bind="css: { 'active-on-queue-finish-menu': finishaction()}">
|
||||
<a href="#" data-toggle="dropdown" onclick="keepOpen(this)">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@@ -102,23 +102,14 @@
|
||||
<li class="divider"></li>
|
||||
<li class="dropdown-header"><span class="glyphicon glyphicon-off"></span> $T('Glitter-onFinish'):</li>
|
||||
<li>
|
||||
<select data-bind="value: onQueueFinish, event: { change: setOnQueueFinish }" class="form-control">
|
||||
<select data-bind="value: finishaction, event: { change: setOnQueueFinish }" class="form-control">
|
||||
<option value=""></option>
|
||||
<optgroup label="$T('eoq-actions')">
|
||||
<option value="shutdown_program">$T('shutdownSab')</option>
|
||||
<!--#if $power_options#-->
|
||||
<option value="shutdown_pc">$T('shutdownPc')</option>
|
||||
<option value="standby_pc">$T('standbyPc')</option>
|
||||
<option value="hibernate_pc">$T('hibernatePc')</option>
|
||||
<!--#end if#-->
|
||||
</optgroup>
|
||||
<optgroup label="$T('eoq-scripts')" data-bind="visible: queue.scriptsList().length > 1">
|
||||
<!-- ko foreach: queue.scriptsList -->
|
||||
<!-- ko if: \$data != glitterTranslate.noneText -->
|
||||
<option data-bind="text: \$data, attr: { value: 'script_'+\$data } " ></option>
|
||||
<!-- /ko -->
|
||||
<!-- /ko -->
|
||||
</optgroup>
|
||||
<option value="shutdown_program">$T('shutdownSab')</option>
|
||||
<!--#if $power_options#-->
|
||||
<option value="shutdown_pc">$T('shutdownPc')</option>
|
||||
<option value="standby_pc">$T('standbyPc')</option>
|
||||
<option value="hibernate_pc">$T('hibernatePc')</option>
|
||||
<!--#end if#-->
|
||||
</select>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -26,13 +26,15 @@
|
||||
<!-- /ko -->
|
||||
<!-- ko foreach: allMessages -->
|
||||
<tr>
|
||||
<td class="table-messages-label">
|
||||
<td class="table-messages-label" data-bind="attr: { 'colspan': 1 + !\$data.hasOwnProperty('clear') }">
|
||||
<span class="label" data-bind="css: 'label-' + css, text: type"></span>
|
||||
<span class="queue-message-text" data-bind="html: text"></span>
|
||||
</td>
|
||||
<!-- ko if: \$data.hasOwnProperty("clear") -->
|
||||
<td class="table-messages-remove">
|
||||
<!-- ko if: \$data.hasOwnProperty("clear") --><a href="#" data-bind="click: clear" class="hover-button"><span class="glyphicon glyphicon-remove"></span></a><!-- /ko -->
|
||||
<a href="#" data-bind="click: clear" class="hover-button"><span class="glyphicon glyphicon-remove"></span></a>
|
||||
</td>
|
||||
<!-- /ko -->
|
||||
</tr>
|
||||
<!-- /ko -->
|
||||
<!-- ko if: !hasMessages() && displayTabbed() -->
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
<!--#from sabnzbd.constants import VALID_ARCHIVES, VALID_NZB_FILES#-->
|
||||
<!--#set $file_exts = ', '.join(VALID_NZB_FILES + VALID_ARCHIVES)#-->
|
||||
<!-- Notifcation box -->
|
||||
<!-- Notification box -->
|
||||
<div class="main-notification-box" style="display: none">
|
||||
<div class="main-notification-box-uploading">
|
||||
<span class="glyphicon glyphicon-open"></span> $T('Glitter-notification-uploading') <span class="main-notification-box-file-count"></span>
|
||||
</div>
|
||||
|
||||
<div class="main-notification-box-uploading-failed">
|
||||
<span class="glyphicon glyphicon-exclamation-sign"></span> $T('Glitter-notification-upload-failed').replace('%s', '') <span class="main-notification-box-file-count"></span>
|
||||
</div>
|
||||
|
||||
<div class="main-notification-box-queue-repair">
|
||||
<span class="glyphicon glyphicon glyphicon-wrench"></span> $T('Glitter-repairQueue')
|
||||
<span class="glyphicon glyphicon-wrench"></span> $T('Glitter-repairQueue')
|
||||
</div>
|
||||
|
||||
<div class="main-notification-box-disconnect">
|
||||
@@ -63,7 +67,7 @@
|
||||
<p><strong>If you encounter an error, please include the log file (click on <span class="glyphicon glyphicon-wrench"></span> ) when contacting us.</strong></p>
|
||||
<span class="glyphicon glyphicon-home"></span> <a href="https://forums.sabnzbd.org/viewforum.php?f=11" target="_blank">SABnzbd Forum</a><br />
|
||||
<span class="glyphicon glyphicon-plane"></span> <a href="https://github.com/sabnzbd/sabnzbd/" target="_blank">SABnzbd on Github</a><br />
|
||||
<span class="glyphicon glyphicon-globe"></span> <a href="https://translations.launchpad.net/sabnzbd" target="_blank">Translations of SABnzbd</a><br />
|
||||
<span class="glyphicon glyphicon-globe"></span> <a href="https://sabnzbd.org/wiki/translate" target="_blank">Translations of SABnzbd</a><br />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -85,74 +89,99 @@
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade in active" id="options-status">
|
||||
<div class="row" data-bind="visible: statusInfo.active_socks5_proxy">
|
||||
<div class="col-sm-6">$T('opt-socks5_proxy_url')   </div>
|
||||
<div class="col-sm-6" data-bind="visible: hasStatusInfo, text: statusInfo.active_socks5_proxy"></div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasStatusInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('dashboard-localIP4')</div>
|
||||
<div class="col-sm-6">$T('dashboard-localIP4') </div>
|
||||
<div class="col-sm-6" data-bind="visible: hasStatusInfo, text: !statusInfo.localipv4() ? '$T('dashboard-connectionError')' : statusInfo.localipv4(), css: { 'options-bad-status' : !statusInfo.localipv4() }"></div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasStatusInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('dashboard-publicIP4')</div>
|
||||
<div class="col-sm-6">$T('dashboard-publicIP4') </div>
|
||||
<div class="col-sm-6" data-bind="visible: hasStatusInfo, text: !statusInfo.publicipv4() ? '$T('dashboard-connectionError')' : statusInfo.publicipv4(), css: { 'options-bad-status ' : !statusInfo.publicipv4() }"></div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasStatusInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('dashboard-IP6')</div>
|
||||
<div class="col-sm-6">$T('dashboard-IP6') </div>
|
||||
<div class="col-sm-6" data-bind="visible: hasStatusInfo, text: statusInfo.ipv6"></div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasStatusInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('dashboard-NameserverDNS')</div>
|
||||
<div class="col-sm-6" data-bind="visible: hasStatusInfo, text: !statusInfo.dnslookup() ? '$T('dashboard-connectionError')' : statusInfo.dnslookup(), css: { 'options-bad-status' : (statusInfo.dnslookup() != 'OK') }"></div>
|
||||
<div class="col-sm-6">$T('dashboard-NameserverDNS') </div>
|
||||
<div class="col-sm-6" data-bind="visible: hasStatusInfo, text: !statusInfo.dnslookup() ? '$T('dashboard-connectionError')' : 'OK', css: { 'options-bad-status' : !statusInfo.dnslookup() }"></div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasStatusInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('cache')</div>
|
||||
<div class="col-sm-6">$T('cache') </div>
|
||||
<div class="col-sm-6">
|
||||
<span data-bind="text: cacheSize"></span> (<span data-bind="text: cacheArticles"></span> $T('Glitter-articles'))
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" data-bind="visible: statusInfo.loadavg()">
|
||||
<div class="col-sm-6">$T('dashboard-loadavg') </div>
|
||||
<div class="col-sm-6">
|
||||
<span data-bind="text: statusInfo.loadavg"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" data-bind="visible: statusInfo.delayed_assembler() > 5">
|
||||
<div class="col-sm-6">$T('dashboard-delayed') </div>
|
||||
<div class="col-sm-6">
|
||||
<span data-bind="visible: statusInfo.delayed_assembler() > 5">$T('dashboard-delayed-disk')</span>
|
||||
<small data-bind="visible: statusInfo.delayed_assembler() > 5">(<span data-bind="text: statusInfo.delayed_assembler"></span>x)</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('dashboard-systemPerformance')</div>
|
||||
<div class="col-sm-6" data-bind="visible: hasPerformanceInfo">
|
||||
<div class="col-sm-6">$T('dashboard-systemPerformance') </div>
|
||||
<div class="col-sm-6 col-dot-overflow" data-bind="visible: hasPerformanceInfo">
|
||||
<span data-bind="text: statusInfo.pystone"></span>
|
||||
<a href="#" data-bind="click: testDiskSpeed" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<small data-bind="truncatedText: statusInfo.cpumodel, length: 25, attr: { 'data-original-title': statusInfo.cpumodel }" data-tooltip="true"></small>
|
||||
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest') (~10 $T('seconds'))"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<small title="$cpumodel $cpusimd" data-tooltip="true">$cpumodel $cpusimd</small>
|
||||
</div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('dashboard-downloadDirSpeed')</div>
|
||||
<div class="col-sm-6" data-bind="visible: hasPerformanceInfo">
|
||||
<div class="col-sm-6">$T('dashboard-downloadDirSpeed') </div>
|
||||
<div class="col-sm-6 col-dot-overflow" data-bind="visible: hasPerformanceInfo">
|
||||
<span data-bind="text: statusInfo.downloaddirspeed()"></span> MB/s
|
||||
<a href="#" class="diskspeed-button" data-bind="click: testDiskSpeed" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<small>(<span data-bind="truncatedText: statusInfo.downloaddir, length: 24, attr: { 'data-original-title': statusInfo.downloaddir }" data-tooltip="true"></span>)</small>
|
||||
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest') (~10 $T('seconds'))"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<small data-bind="text: statusInfo.downloaddir, attr: { 'data-original-title': statusInfo.downloaddir }" data-tooltip="true"></small>
|
||||
</div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('dashboard-completeDirSpeed')</div>
|
||||
<div class="col-sm-6" data-bind="visible: hasPerformanceInfo">
|
||||
<div class="col-sm-6">$T('dashboard-completeDirSpeed') </div>
|
||||
<div class="col-sm-6 col-dot-overflow" data-bind="visible: hasPerformanceInfo">
|
||||
<span data-bind="text: statusInfo.completedirspeed()"></span> MB/s
|
||||
<a href="#" class="diskspeed-button" data-bind="click: testDiskSpeed" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<small>(<span data-bind="truncatedText: statusInfo.completedir, length: 24, attr: { 'data-original-title': statusInfo.completedir }" data-tooltip="true"></span>)</small>
|
||||
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest') (~10 $T('seconds'))"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<small data-bind="text: statusInfo.completedir, attr: { 'data-original-title': statusInfo.completedir }" data-tooltip="true"></small>
|
||||
</div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('dashboard-internetBandwidth')</div>
|
||||
<div class="col-sm-6">$T('dashboard-internetBandwidth') </div>
|
||||
<div class="col-sm-6" data-bind="visible: hasPerformanceInfo">
|
||||
<span data-bind="text: statusInfo.internetbandwidth()"></span> MB/s
|
||||
<a href="#" class="diskspeed-button" data-bind="click: testDiskSpeed" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<small>(<span data-bind="text: statusInfo.internetbandwidth()*8"></span> Mbps)</small>
|
||||
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest') (~10 $T('seconds'))"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<small><span data-bind="text: statusInfo.internetbandwidth()*8"></span> Mbps</small>
|
||||
</div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('platform') </div>
|
||||
<div class="col-sm-6">
|
||||
$platform
|
||||
</div>
|
||||
</div>
|
||||
<div class="row test-download">
|
||||
<div class="col-sm-6">$T('dashboard-testDownload')</div>
|
||||
<div class="col-sm-6">$T('dashboard-testDownload') </div>
|
||||
<div class="col-sm-6">
|
||||
<a href="#" class="btn btn-default" data-bind="click: testDownload" data-size="100MB" data-tooltip="true" data-placement="top" title="$T('dashboard-testDownload-explain')"><span class="glyphicon glyphicon-download-alt"></span> 100 MB</a>
|
||||
<a href="#" class="btn btn-default" data-bind="click: testDownload" data-size="1000MB" data-tooltip="true" data-placement="top" title="$T('dashboard-testDownload-explain')"><span class="glyphicon glyphicon-download-alt"></span> 1000 MB</a>
|
||||
<a href="#" class="btn btn-default" data-bind="click: testDownload" data-size="1000MB" data-tooltip="true" data-placement="top" title="$T('dashboard-testDownload-explain')"><span class="glyphicon glyphicon-download-alt"></span> 1 GB</a>
|
||||
<a href="#" class="btn btn-default" data-bind="click: testDownload" data-size="10GB" data-tooltip="true" data-placement="top" title="$T('dashboard-testDownload-explain')"><span class="glyphicon glyphicon-download-alt"></span> 10 GB</a>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
@@ -168,14 +197,14 @@
|
||||
</div>
|
||||
<div class="row options-function-box">
|
||||
<div class="col-sm-6">
|
||||
<a href="./status/showlog?apikey=$apikey" target="_blank" class="btn btn-default" data-tooltip="true" data-placement="top" title="$T('Glitter-logText')">
|
||||
<a href="./api?mode=showlog&apikey=$apikey" target="_blank" class="btn btn-default" data-tooltip="true" data-placement="top" title="$T('Glitter-logText')">
|
||||
<span class="glyphicon glyphicon-file"></span> $T('link-showLog')
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" data-tooltip="true" data-placement="top" title="$T('logging')">
|
||||
<span class="input-group-addon"><span class="glyphicon glyphicon-comment"></span></span>
|
||||
<select class="form-control" data-bind="value: statusInfo.loglevel">
|
||||
<select class="form-control" data-bind="value: loglevel">
|
||||
<option value="0">$T('log-errWarn')</option>
|
||||
<option value="1">$T('log-info')</option>
|
||||
<option value="2">$T('log-debug')</option>
|
||||
@@ -206,17 +235,26 @@
|
||||
</div>
|
||||
<div class="row" data-bind="visible: serverssl">
|
||||
<div class="col-sm-6">$T('srv-ssl')</div>
|
||||
<div class="col-sm-6">
|
||||
<span class="glyphicon glyphicon-ok"></span> <span data-bind="text: serversslinfo"></span>
|
||||
<div class="col-sm-6 col-dot-overflow">
|
||||
<span class="glyphicon glyphicon-ok"></span>
|
||||
<span data-bind="text: serversslinfo"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6"># $T('connections')</div>
|
||||
<div class="col-sm-6">
|
||||
<span data-bind="text: serverconnections().length"></span> /
|
||||
<span data-bind="text: servertotalconn"></span>
|
||||
<span data-bind="text: servertotalconn"></span><br>
|
||||
<!-- ko if: serveripaddress() -->
|
||||
<span data-bind="text: servercanonname"></span><br>
|
||||
<span data-bind="text: serveripaddress"></span>
|
||||
<!-- /ko -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('Glitter-speed')</div>
|
||||
<div class="col-sm-6"><span data-bind="text: serverbps"></span>B/s</div>
|
||||
</div>
|
||||
<div class="row" data-bind="visible: servererror()">
|
||||
<div class="col-sm-12">
|
||||
<div class="alert alert-danger">
|
||||
@@ -226,11 +264,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" data-bind="visible: !isFinite(serveractiveconn())">
|
||||
<div class="row" data-bind="visible: serverwarning()">
|
||||
<div class="col-sm-12">
|
||||
<div class="alert alert-warning">
|
||||
<span class="glyphicon glyphicon-info-sign"></span>
|
||||
<span data-bind="text: serveractiveconn()"></span>
|
||||
<span data-bind="text: serverwarning()"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -279,8 +317,8 @@
|
||||
<tr>
|
||||
<td><span class="glyphicon glyphicon-folder-open"></span></td>
|
||||
<td class="row-wrap-text"><strong data-bind="html: \$data"></strong></td>
|
||||
<td><a href="#" data-bind="click: \$root.folderProcess" data-action="add" class="hover-button" data-tooltip="true" data-placement="left" title="$T('Glitter-backToQueue')"><span class="glyphicon glyphicon-plus-sign"></span></a></td>
|
||||
<td><a href="#" data-bind="click: \$root.folderProcess" data-action="delete" class="hover-button" data-tooltip="true" data-placement="left" title="$T('Glitter-deleteJobAndFolders')"><span class="glyphicon glyphicon-trash"></span></a></td>
|
||||
<td><a href="#" data-bind="click: \$root.folderProcess" data-action="add_orphan" class="hover-button" data-tooltip="true" data-placement="left" title="$T('Glitter-backToQueue')"><span class="glyphicon glyphicon-plus-sign"></span></a></td>
|
||||
<td><a href="#" data-bind="click: \$root.folderProcess" data-action="delete_orphan" class="hover-button" data-tooltip="true" data-placement="left" title="$T('Glitter-deleteJobAndFolders')"><span class="glyphicon glyphicon-trash"></span></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -342,7 +380,6 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options-switch"></div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-6 control-label">$T('Glitter-dateFormat')</label>
|
||||
<div class="col-sm-4">
|
||||
@@ -367,8 +404,7 @@
|
||||
<span class="label label-warning">> 1200 pixels</span>
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="general-extra-column" class="form-control" data-bind="value: extraQueueColumn">
|
||||
<option value="">$T('none')</option>
|
||||
<select name="general-extra-column" class="form-control-multiselect form-control" data-bind="selectedOptions: extraQueueColumns" multiple="true">
|
||||
<option value="category">$T('category')</option>
|
||||
<option value="priority">$T('priority')</option>
|
||||
<option value="processing">$T('swtag-pp')</option>
|
||||
@@ -383,8 +419,7 @@
|
||||
<span class="label label-warning">> 1200 pixels</span>
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="general-extra-column" class="form-control" data-bind="value: extraHistoryColumn">
|
||||
<option value="">$T('none')</option>
|
||||
<select name="general-extra-column" class="form-control-multiselect form-control" data-bind="selectedOptions: extraHistoryColumns" multiple="true">
|
||||
<option value="category">$T('category')</option>
|
||||
<option value="size">$T('size')</option>
|
||||
<option value="speed">$T('Glitter-speed')</option>
|
||||
@@ -399,6 +434,14 @@
|
||||
<input type="checkbox" name="displayCompact" value="true" data-bind="checked: displayCompact" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-checkbox">
|
||||
<label class="col-sm-6 control-label">
|
||||
$T("Glitter-displayFullWidth")
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="checkbox" name="displayFullWidth" value="true" data-bind="checked: displayFullWidth" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-checkbox">
|
||||
<label class="col-sm-6 control-label">
|
||||
$T("Glitter-displayTabbed")
|
||||
@@ -423,6 +466,16 @@
|
||||
<input type="checkbox" name="confirmDeleteHistory" value="true" data-bind="checked: confirmDeleteHistory" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-checkbox">
|
||||
<label class="col-sm-6 control-label">
|
||||
$T("Glitter-keyboardShortcuts")
|
||||
<span class="glyphicon glyphicon-question-sign" data-tooltip="true" data-placement="top" data-html="true"
|
||||
data-original-title="P: $T('link-pause')<br>A: $T('Glitter-addNZB')<br>S: $T('Glitter-statusInterfaceOptions')<br>C: $T('menu-config')<br>$T('Glitter-keyboardShortcuts-arrows')"></span>
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="checkbox" name="keyboardShortcuts" value="true" data-bind="checked: keyboardShortcuts" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -434,14 +487,14 @@
|
||||
|
||||
<div id="modal-add-nzb" class="modal fade" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form class="modal-content" data-bind="submit: addNZB">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">$T('Glitter-addNZB')</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="modal-body form-horizontal">
|
||||
<div class="row">
|
||||
<form data-bind="submit: addNZBFromURL" class="col-sm-6">
|
||||
<div class="col-sm-6">
|
||||
<fieldset>
|
||||
<legend class="row-wrap-text">$T('Glitter-addFromURL')</legend>
|
||||
<div class="input-group" data-tooltip="true" data-placement="bottom" title="$file_exts">
|
||||
@@ -451,8 +504,8 @@
|
||||
</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
<form data-bind="submit: addNZBFromFileForm" class="col-sm-6">
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<fieldset>
|
||||
<legend class="row-wrap-text">$T('Glitter-addFromFile')</legend>
|
||||
<div class="input-group" data-tooltip="true" data-placement="bottom" title="$file_exts">
|
||||
@@ -466,37 +519,61 @@
|
||||
</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<hr />
|
||||
<div class="row form-horizontal">
|
||||
<label class="col-sm-6 control-label">$T('Glitter-addnzbFilename')</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="nzbname" id="nzbname" placeholder="$T('name')" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="clearfix"></div>
|
||||
<div class="add-nzb-inputbox" title="$T('category')" data-tooltip="true" data-placement="left">
|
||||
<span class="glyphicon glyphicon-tag"></span>
|
||||
<select name="Category" class="form-control" data-bind="options: queue.categoriesList, optionsValue: 'catValue', optionsText: 'catText',"></select>
|
||||
<hr />
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('name')</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="nzbname" id="nzbname" placeholder="$T('Glitter-addnzbFilename')" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="add-nzb-inputbox" title="$T('priority')" data-tooltip="true" data-placement="left">
|
||||
<span class="glyphicon glyphicon-sort-by-attributes-alt"></span>
|
||||
<select name="Priority" class="form-control" data-bind="options: queue.priorityOptions, optionsValue: 'value', optionsText: 'name', optionsCaption: '$T('default')'"></select>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('srv-password')</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="password" id="password" placeholder="$T('srv-optional')" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="add-nzb-inputbox" title="$T('swtag-pp')" data-tooltip="true" data-placement="left">
|
||||
<span class="glyphicon glyphicon-check"></span>
|
||||
<select name="Processing" class="form-control" data-bind="options: queue.processingOptions, optionsValue: 'value', optionsText: 'name', optionsCaption: '$T('default')'"></select>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('category')</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="Category" class="form-control" data-bind="options: queue.categoriesList, optionsValue: 'catValue', optionsText: 'catText', optionsCaption: ''"></select>
|
||||
<span class="glyphicon glyphicon-tag"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="add-nzb-inputbox" title="$T('eoq-scripts')" data-tooltip="true" data-placement="left">
|
||||
<span class="glyphicon glyphicon-flash"></span>
|
||||
<select name="Post-processing" class="form-control" data-bind="options: queue.scriptsList, optionsCaption: '$T('default')'"></select>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('priority')</label>
|
||||
<div class="col-sm-6">
|
||||
<!-- This list is different from the one during download! -->
|
||||
<select name="Priority" class="form-control">
|
||||
<option value=""></option>
|
||||
<option value="2">$T('pr-force')</option>
|
||||
<option value="1">$T('pr-high')</option>
|
||||
<option value="0">$T('pr-normal')</option>
|
||||
<option value="-1">$T('pr-low')</option>
|
||||
<option value="-2" >$T('pr-paused')</option>
|
||||
</select>
|
||||
<span class="glyphicon glyphicon-sort-by-attributes-alt"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('swtag-pp')</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="Processing" class="form-control" data-bind="options: queue.processingOptions, optionsValue: 'value', optionsText: 'name', optionsCaption: ''"></select>
|
||||
<span class="glyphicon glyphicon-check"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('eoq-scripts')</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="Post-processing" class="form-control" data-bind="options: queue.scriptsList, optionsCaption: '', optionsValue: 'scriptValue', optionsText: 'scriptText', enable: (queue.scriptsList().length > 1)"></select>
|
||||
<span class="glyphicon glyphicon-flash"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -568,6 +645,59 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-delete-queue-job" class="modal modal-delete-job fade" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title row-wrap-text">$T('removeNZB-Files')</h4>
|
||||
</div>
|
||||
<form data-bind="submit: queue.removeDownloads">
|
||||
<div class="modal-body">
|
||||
$T('confirm-delete')
|
||||
|
||||
<ul data-bind="foreach: queue.deleteItems">
|
||||
<li data-bind="text: name"></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">$T('cancel')</button>
|
||||
<button type="submit" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span> $T('nzo-delete')</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-delete-history-job" class="modal modal-delete-job fade" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title row-wrap-text">$T('nzo-delete')</h4>
|
||||
</div>
|
||||
<form data-bind="submit: history.removeDownloads">
|
||||
<div class="modal-body">
|
||||
$T('confirm-delete')
|
||||
|
||||
<ul data-bind="foreach: history.deleteItems">
|
||||
<li data-bind="text: historyStatus.name"></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="checkbox" data-bind="visible: !history.showArchive()">
|
||||
<label>
|
||||
<input type="checkbox" data-bind="checked: history.permanentlyDelete"> <span>$T('permanently-delete')</span>
|
||||
</label>
|
||||
</div>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">$T('cancel')</button>
|
||||
<button type="submit" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span> $T('nzo-delete')</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-retry-job" class="modal modal-small fade" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
@@ -598,6 +728,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
$T('Glitter-retryNoChecks')
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-default"><span class="glyphicon glyphicon-repeat"></span> $T('button-retry')</button>
|
||||
@@ -645,13 +778,13 @@
|
||||
<td><a href="https://github.com/sabnzbd/sabnzbd" target="_blank">https://github.com/sabnzbd/sabnzbd/</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>$T('menu-irc'):</strong></td>
|
||||
<td><strong>$T('menu-live-chat'):</strong></td>
|
||||
<td><a href="https://sabnzbd.org/live-chat" target="_blank">https://sabnzbd.org/live-chat</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr/>
|
||||
<p><small>Copyright (C) 2007-2020 The SABnzbd Team <team@sabnzbd.org><br/>$T('yourRights') </small></p>
|
||||
<p><small>Copyright © 2007-2025 by The SABnzbd-Team (<a href="https://sabnzbd.org/" target="_blank">sabnzbd.org</a>)<br/>$T('yourRights') </small></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -670,11 +803,18 @@
|
||||
<button type="button" class="btn btn-danger" data-bind="click: history.emptyHistory" data-action="history-purge-completed"><span class="glyphicon glyphicon-floppy-saved"></span> $T('purgeCompl')</button><hr />
|
||||
<button type="button" class="btn btn-danger" data-bind="click: history.emptyHistory" data-action="history-purge-page"><span class="glyphicon glyphicon-check"></span> $T('purgePage') <span class="label label-default" data-bind="text: history.historyItems().length"></span></button>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" data-bind="checked: history.permanentlyDelete"> <span>$T('permanently-delete')</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal_custom_pause" class="modal modal-small fade" tabindex="-1">
|
||||
<div id="modal-custom-pause" class="modal modal-small fade" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
|
||||
@@ -9,22 +9,16 @@
|
||||
</a>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<!--#if $loadavg#-->
|
||||
<div class="info-container-box" title="$T('ft-sysload') - $T('menu-config') ➜ $T('cmenu-special') ➜ show_sysload">
|
||||
<span class="glyphicon glyphicon-record"></span>
|
||||
<span data-bind="text: systemLoad"></span>
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
<!-- ko if: (queueDataLeft() != '') -->
|
||||
<div class="info-container-box">
|
||||
<span class="glyphicon glyphicon-save"></span>
|
||||
<span data-bind="text: queueDataLeft"></span> $T('Glitter-left')
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<!-- ko if: (quotaLimit() != 0) -->
|
||||
<!-- ko if: (parseInt(quotaLimit()) != 0) -->
|
||||
<div class="info-container-box">
|
||||
<span data-bind="css: { 'queue-error-info' : (parseInt(quotaLimitLeft())<=0) }">
|
||||
<span class="glyphicon glyphicon-log-in"></span> <span data-bind="text: quotaLimitLeft"></span>B / <span data-bind="text: quotaLimit"></span>B $T('quota-left')
|
||||
<span class="glyphicon glyphicon-log-in"></span> <span data-bind="text: quotaLimitLeft"></span> / <span data-bind="text: quotaLimit"></span> $T('quota-left')
|
||||
</span>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
@@ -52,6 +46,7 @@
|
||||
<span class="glyphicon glyphicon-tasks" data-tooltip="true" data-placement="left" title="$T('Glitter-multiOperations')"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" data-action="sortRemainingAsc" data-bind="click: queue.queueSorting">$T('Glitter-sortRemaining')</a></li>
|
||||
<li><a href="#" data-action="sortAgeAsc" data-bind="click: queue.queueSorting">$T('Glitter-sortAgeAsc')</a></li>
|
||||
<li><a href="#" data-action="sortAgeDesc" data-bind="click: queue.queueSorting">$T('Glitter-sortAgeDesc')</a></li>
|
||||
<li><a href="#" data-action="sortNameAsc" data-bind="click: queue.queueSorting">$T('Glitter-sortNameAsc')</a></li>
|
||||
@@ -67,8 +62,10 @@
|
||||
<tr>
|
||||
<th style="width: 25px;"></th>
|
||||
<th></th>
|
||||
<th class="table-header-extra" data-bind="css: { 'table-extra-header-visible' : extraQueueColumn }"></th>
|
||||
<th class="table-header-progress" data-bind="css: { 'table-header-progress-smaller' : extraQueueColumn }"></th>
|
||||
<!-- ko foreach: extraQueueColumns -->
|
||||
<th class="table-header-extra"></th>
|
||||
<!-- /ko -->
|
||||
<th class="table-header-progress" data-bind="css: { 'table-header-progress-smaller' : extraQueueColumns().length }"></th>
|
||||
<th style="width: 85px;"></th>
|
||||
<th style="width: 60px;"></th>
|
||||
</tr>
|
||||
@@ -76,7 +73,7 @@
|
||||
<!-- ko if: !hasQueue() -->
|
||||
<tbody class="no-downloads">
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<td colspan="6" data-bind="attr: { 'colspan': 5 + extraQueueColumns().length }">
|
||||
<a href="#modal-add-nzb" class="hover-button" data-toggle="modal">
|
||||
<span title="$T('Glitter-dragAndDrop')" data-tooltip="true"><span class="glyphicon glyphicon-plus-sign"></span> $T('Glitter-addNZB')</span>
|
||||
</a>
|
||||
@@ -93,6 +90,9 @@
|
||||
</td>
|
||||
<td class="name">
|
||||
<div class="row-wrap-text" data-bind="visible: !editingName(), css: { 'direct-unpack-text': direct_unpack }">
|
||||
<!-- ko foreach: labels -->
|
||||
<span class="label label-warning" data-bind="text: \$data" ></span>
|
||||
<!-- /ko -->
|
||||
<span data-bind="text: name, attr: { 'title': name_title }"></span>
|
||||
<!-- ko if: password() -->
|
||||
<small class="queue-item-password">
|
||||
@@ -104,7 +104,7 @@
|
||||
<form data-bind="submit: editingNameSubmit">
|
||||
<input type="text" data-bind="value: nameForEdit, visible: editingName(), hasfocus: editingName" />
|
||||
</form>
|
||||
<div class="name-icons direct-unpack hover-button" data-bind="visible: direct_unpack">
|
||||
<div class="name-icons direct-unpack hover-button" data-bind="visible: direct_unpack() && !editingName()">
|
||||
<span class="glyphicon glyphicon-compressed"></span> <span data-bind="text: direct_unpack"></span>
|
||||
</div>
|
||||
<div class="name-options" data-bind="visible: !editingName(), css: { disabled: isGrabbing() }">
|
||||
@@ -115,10 +115,11 @@
|
||||
<small data-bind="text: avg_age"></small>
|
||||
</div>
|
||||
</td>
|
||||
<!-- ko foreach: parent.parent.extraQueueColumns -->
|
||||
<td class="row-extra-text">
|
||||
<div class="row-wrap-text" data-bind="text: extraText">
|
||||
</div>
|
||||
<div class="row-wrap-text" data-bind="text: \$parent.showColumn(\$data)"></div>
|
||||
</td>
|
||||
<!-- /ko -->
|
||||
<td class="progress-indicator">
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-info" data-bind="attr: { 'style': 'width: ' + percentage() + '%; background-color: ' + progressColor() + ';' }">
|
||||
@@ -156,13 +157,13 @@
|
||||
</li>
|
||||
<li title="$T('eoq-scripts')" data-tooltip="true" data-placement="left">
|
||||
<span class="glyphicon glyphicon-flash"></span>
|
||||
<select name="Post-processing" class="form-control" data-bind="options: parent.scriptsList, value: script, event: { change: changeScript }, enable: (parent.scriptsList().length > 1)"></select>
|
||||
<select name="Post-processing" class="form-control" data-bind="options: parent.scriptsList, value: script, optionsValue: 'scriptValue', optionsText: 'scriptText', event: { change: changeScript }, enable: (parent.scriptsList().length > 1)"></select>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- /ko -->
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<a href="#" class="hover-button" title="$T('removeNZB-Files')" data-bind="click: removeDownload"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
<a href="#" class="hover-button" title="$T('removeNZB-Files')" data-bind="click: parent.triggerRemoveDownload"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -170,22 +171,28 @@
|
||||
|
||||
<form class="multioperations-selector" data-bind="visible: (hasQueue() && queue.isMultiEditing())" style="display: none;">
|
||||
<div class="add-nzb-inputbox add-nzb-inputbox-small add-nzb-inputbox-options">
|
||||
<label for="multiedit-checkall">
|
||||
<input type="checkbox" name="multieditCheckAll" id="multiedit-checkall" title="$T('Glitter-checkAll')" data-bind="click: queue.checkAllJobs" data-tooltip="true" data-placement="top" />
|
||||
<label for="multiedit-checkall-queue">
|
||||
<input type="checkbox" name="multieditCheckAll" id="multiedit-checkall-queue" title="$T('Glitter-checkAll')" data-bind="click: queue.checkAllJobs" data-tooltip="true" data-placement="top" />
|
||||
</label>
|
||||
<a href="#" class="hover-button" data-bind="click: queue.doMultiDelete">
|
||||
<a href="#" class="hover-button" title="$T('removeNZB-Files')" data-bind="click: queue.doMultiDelete" data-tooltip="true" data-placement="top">
|
||||
<span class="glyphicon glyphicon-trash"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="add-nzb-inputbox add-nzb-inputbox-small">
|
||||
<label for="multiedit-play">
|
||||
<label for="multiedit-play" data-bind="event: { mousedown: queue.handleMultiEditStatusMouseDown }">
|
||||
<input type="radio" name="multiedit-status" value="resume" id="multiedit-play" data-bind="event: { change: queue.doMultiEditUpdate }" />
|
||||
<span class="glyphicon glyphicon-play" title="$T('link-resume')" data-tooltip="true" data-placement="top"></span>
|
||||
</label>
|
||||
<label for="multiedit-pause">
|
||||
<label for="multiedit-pause" data-bind="event: { mousedown: queue.handleMultiEditStatusMouseDown }">
|
||||
<input type="radio" name="multiedit-status" value="pause" id="multiedit-pause" data-bind="event: { change: queue.doMultiEditUpdate }" />
|
||||
<span class="glyphicon glyphicon-pause" title="$T('link-pause')" data-tooltip="true" data-placement="top"></span>
|
||||
</label>
|
||||
<a href="#" class="hover-button" title="$T('Glitter-top')" data-bind="click: queue.doMultiMoveToTop" data-tooltip="true" data-placement="top">
|
||||
<span class="glyphicon glyphicon-chevron-up"></span>
|
||||
</a>
|
||||
<a href="#" class="hover-button" title="$T('Glitter-bottom')" data-bind="click: queue.doMultiMoveToBottom" data-tooltip="true" data-placement="top">
|
||||
<span class="glyphicon glyphicon-chevron-down"></span>
|
||||
</a>
|
||||
<span class="label label-default" data-bind="text: queue.multiEditItems().length">0</span>
|
||||
</div>
|
||||
<div class="add-nzb-inputbox-clear"></div>
|
||||
@@ -203,7 +210,7 @@
|
||||
</div>
|
||||
<div class="add-nzb-inputbox" data-tooltip="true" data-placement="top" title="$T('eoq-scripts')">
|
||||
<span class="glyphicon glyphicon-flash"></span>
|
||||
<select name="Post-processing" class="form-control" data-bind="options: queue.scriptsList, optionsCaption: '', event: { change: queue.doMultiEditUpdate }"></select>
|
||||
<select name="Post-processing" class="form-control" data-bind="options: queue.scriptsList, optionsValue: 'scriptValue', optionsText: 'scriptText', optionsCaption: '', event: { change: queue.doMultiEditUpdate }"></select>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</form>
|
||||
@@ -220,4 +227,4 @@
|
||||
<span data-bind="text: page"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<!--#set $active_lang=$active_lang.replace('_', '-').lower()#-->
|
||||
<html lang="$active_lang" id="sabnzbd" data-bind="filedrop: { overlaySelector: '.main-filedrop', onFileDrop: addNZBFromFile }">
|
||||
<html lang="$active_lang" <!--#if $rtl#-->dir="rtl"<!--#end if#--> id="sabnzbd" data-bind="filedrop: { overlaySelector: '.main-filedrop', onFileDrop: addNZBFromFile }">
|
||||
<head>
|
||||
<!--
|
||||
Glitter V2
|
||||
@@ -36,7 +36,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="./static/bootstrap/css/bootstrap.min.css?v=$version" />
|
||||
<link rel="stylesheet" type="text/css" href="./static/stylesheets/glitter.css?v=$version" />
|
||||
<link rel="stylesheet" type="text/css" href="./static/stylesheets/glitter.mobile.css?v=$version" media="all and (max-width: 768px)" />
|
||||
<!--#if $color_scheme not in ('Default', '') #-->
|
||||
<!--#if $color_scheme not in ('Light', '') #-->
|
||||
<link rel="stylesheet" type="text/css" href="./static/stylesheets/colorschemes/${color_scheme}.css?v=$version"/>
|
||||
<!--#end if#-->
|
||||
|
||||
@@ -52,28 +52,21 @@
|
||||
var glitterTranslate = new Object();
|
||||
glitterTranslate.paused = "$T('post-Paused')";
|
||||
glitterTranslate.left = "$T('Glitter-left')";
|
||||
glitterTranslate.clearWarn = "$T('Glitter-confirmClearWarnings')";
|
||||
glitterTranslate.clearOrphanWarning = "$T('Glitter-clearOrphanWarning')";
|
||||
glitterTranslate.pausePromptFail = "$T('Glitter-pausePromptFail')"
|
||||
glitterTranslate.pauseFor = "$T('pauseFor')"
|
||||
glitterTranslate.minutes = "$T('mins')"
|
||||
glitterTranslate.shutdown = "$T('shutdownOK?')";
|
||||
glitterTranslate.restart = "$T('explain-Restart') $T('explain-needNewLogin')".replace(/\<br(\s*\/|)\>/g, '\n');
|
||||
glitterTranslate.repair = "$T('explain-Repair')".replace(/<br \/>/g, "\n").replace(/"/g,'"');
|
||||
glitterTranslate.removeDown = "$T('Glitter-confirmClearDownloads')";
|
||||
glitterTranslate.removeDow1 = "$T('Glitter-confirmClear1Download')";
|
||||
glitterTranslate.confirm = "$T('confirm')";
|
||||
glitterTranslate.markComplete = "$T('button-mark-completed')";
|
||||
glitterTranslate.renameAbort = "$T('Glitter-confirmAbortDirectUnpack')\n$T('confirm')";
|
||||
glitterTranslate.retryAll = "$T('link-retryAll')?";
|
||||
glitterTranslate.fetch = "$T('Glitter-fetch')";
|
||||
glitterTranslate.encrypted = "$T('Glitter-encrypted')";
|
||||
glitterTranslate.duplicate = "$T('Glitter-duplicate')";
|
||||
glitterTranslate.tooLarge = "$T('Glitter-tooLarge')";
|
||||
glitterTranslate.unwanted = "$T('Glitter-unwanted')";
|
||||
glitterTranslate.incomplete = "$T('Glitter-incomplete')";
|
||||
glitterTranslate.filtered = "$T('Glitter-filtered')";
|
||||
glitterTranslate.waitSec = "$T('Glitter-waitSec')";
|
||||
glitterTranslate.checking = "$T('post-Checking')";
|
||||
glitterTranslate.misingArt = "$T('missingArt')";
|
||||
glitterTranslate.noSelect = "$T('Glitter-noSelect')";
|
||||
glitterTranslate.sendThanks = "$T('Glitter-sendThanks')";
|
||||
glitterTranslate.fetchingURL = "$T('Glitter-addFromURL')"
|
||||
glitterTranslate.chooseFile = "$T('Glitter-chooseFile')";
|
||||
glitterTranslate.orphanedJobsMsg = "$T('explain-orphans')";
|
||||
glitterTranslate.useCache = "$T('explain-cache_limitstr').replace("64M", "256M").replace("128M", "512M")";
|
||||
@@ -101,7 +94,9 @@
|
||||
glitterTranslate.status['Repair'] = "$T('stage-repair')";
|
||||
glitterTranslate.status['Filejoin'] = "$T('stage-filejoin')";
|
||||
glitterTranslate.status['Unpack'] = "$T('stage-unpack')";
|
||||
glitterTranslate.status['Deobfuscate'] = "$T('stage-deobfuscate')";
|
||||
glitterTranslate.status['Script'] = "$T('stage-script')";
|
||||
glitterTranslate.status['RSS'] = "$T('stage-rss')";
|
||||
glitterTranslate.status['Source'] = "$T('stage-source')";
|
||||
glitterTranslate.status['Servers'] = "$T('stage-servers')";
|
||||
glitterTranslate.status['INFO'] = "$T('log-info')".replace('+', '').toUpperCase();
|
||||
@@ -122,14 +117,16 @@
|
||||
glitterTranslate.priority['Stop'] = "$T('pr-stop')";
|
||||
</script>
|
||||
|
||||
<!-- Inclusion is faster than external scripts. We load momentJS locale seperatly so failure won't break anything -->
|
||||
<!-- Inclusion is faster than external scripts. We load momentJS locale separately so failure won't break anything -->
|
||||
<script type="text/javascript">
|
||||
<!--#include raw $webdir + "/static/javascripts/jquery.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/jquery-3.5.1.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/jquery-ui.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/jquery.peity.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/moment.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/knockout-latest.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/jquery.hotkeys.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/moment-2.26.0.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/knockout-3.5.1.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/knockout-extensions.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/search-query-parser.js"#-->
|
||||
<!--#include raw $webdir + "/static/bootstrap/js/bootstrap.min.js"#-->
|
||||
<!--#include $webdir + "/static/javascripts/glitter.js"#-->
|
||||
</script>
|
||||
@@ -149,10 +146,10 @@
|
||||
<a href="#queue-tab" data-toggle="tab">$T('menu-queue') <span class="badge" data-bind="text: queue.totalItems"></span></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#history-tab" data-toggle="tab">$T('menu-history')<span class="badge" data-bind="text: history.totalItems"></span></a>
|
||||
<a href="#history-tab" data-toggle="tab">$T('menu-history') <span class="badge badge-info" data-bind="text: history.ppItems, visible: history.ppItems"></span><span class="badge" data-bind="text: history.totalItems"></span></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#queue-messages" data-toggle="tab">$T('warnings')<span class="badge" data-bind="text: hasMessages, css: { 'badge-warning': hasMessages() }"></span></a>
|
||||
<a href="#queue-messages" data-toggle="tab">$T('warnings') <span class="badge" data-bind="text: hasMessages, css: { 'badge-warning': hasMessages() }"></span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
<!--#if $paused#-->
|
||||
<!--#if $pause_int != '0' #-->
|
||||
<!--#from math import floor#-->
|
||||
|
||||
<!--#set pauseSplit = $pause_int.split(':')#-->
|
||||
<!--#set seconds = int(pauseSplit[0]) * 60 + int(pauseSplit[1])#-->
|
||||
<!--#set hours = floor(seconds/3600)#-->
|
||||
<!--#set minutes = floor((seconds - hours * 3600) / 60)#-->
|
||||
<!--#set seconds = seconds - minutes * 60 - hours * 3600#-->
|
||||
|
||||
<!--#if seconds < 10 #-->
|
||||
<!--#set seconds = '0' + str(int(seconds)) #-->
|
||||
<!--#else#-->
|
||||
<!--#set seconds = str(int(seconds)) #-->
|
||||
<!--#end if#-->
|
||||
|
||||
<!--#if (minutes < 10) & (hours > 0) #-->
|
||||
<!--#set minutes = '0' + str(int(minutes)) #-->
|
||||
<!--#else#-->
|
||||
<!--#set minutes = str(int(minutes)) #-->
|
||||
<!--#end if#-->
|
||||
|
||||
<!--#if hours > 0 #-->
|
||||
<!--#set timeString = str(int(hours)) + ":" + minutes + ":" + seconds#-->
|
||||
<!--#else#-->
|
||||
<!--#set timeString = minutes + ":" + seconds#-->
|
||||
<!--#end if#-->
|
||||
<!--#end if#-->
|
||||
|
||||
$T('post-Paused') <!--#if $pause_int != '0' #-->($timeString) <!--#end if#-->
|
||||
<!--#if float($mbleft) > 0#-->
|
||||
- $sizeleft $T('Glitter-left')
|
||||
<!--#end if#-->
|
||||
- SABnzbd
|
||||
<!--#else if float($mbleft) < 0.1#-->
|
||||
SABnzbd
|
||||
<!--#else#-->
|
||||
${speed}B/s - $sizeleft $T('Glitter-left') - SABnzbd
|
||||
<!--#end if#-->
|
||||
|||<!--#echo "%.0f" % float($kbpersec)#-->
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
Base variables and functions
|
||||
**/
|
||||
var fadeOnDeleteDuration = 400; // ms after deleting a row
|
||||
var isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
|
||||
|
||||
// To avoid problems when localStorage is disabled
|
||||
@@ -25,7 +24,7 @@ if(isMobile) {
|
||||
}
|
||||
|
||||
// Basic API-call
|
||||
function callAPI(data) {
|
||||
function callAPI(data, timeout = 10000) {
|
||||
// Fill basis var's
|
||||
data.output = "json";
|
||||
data.apikey = apiKey;
|
||||
@@ -34,65 +33,12 @@ function callAPI(data) {
|
||||
type: "GET",
|
||||
cache: false,
|
||||
data: data,
|
||||
timeout: 10000 // Wait a little longer on mobile connections
|
||||
timeout: timeout
|
||||
});
|
||||
|
||||
return $.when(ajaxQuery);
|
||||
}
|
||||
|
||||
// Special API call
|
||||
function callSpecialAPI(url, data) {
|
||||
// Did we get input?
|
||||
if(data == undefined) data = {};
|
||||
// Fill basis var's
|
||||
data.output = "json";
|
||||
data.apikey = apiKey;
|
||||
var ajaxQuery = $.ajax({
|
||||
url: url,
|
||||
type: "GET",
|
||||
cache: false,
|
||||
data: data
|
||||
});
|
||||
|
||||
return $.when(ajaxQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
Handle visibility changes so we
|
||||
do only incremental update when not visible
|
||||
**/
|
||||
var pageIsVisible = true;
|
||||
// Set the name of the hidden property and the change event for visibility
|
||||
var hidden, visibilityChange;
|
||||
if(typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
|
||||
hidden = "hidden";
|
||||
visibilityChange = "visibilitychange";
|
||||
} else if(typeof document.mozHidden !== "undefined") {
|
||||
hidden = "mozHidden";
|
||||
visibilityChange = "mozvisibilitychange";
|
||||
} else if(typeof document.msHidden !== "undefined") {
|
||||
hidden = "msHidden";
|
||||
visibilityChange = "msvisibilitychange";
|
||||
} else if(typeof document.webkitHidden !== "undefined") {
|
||||
hidden = "webkitHidden";
|
||||
visibilityChange = "webkitvisibilitychange";
|
||||
}
|
||||
|
||||
// Set the global visibility
|
||||
function handleVisibilityChange() {
|
||||
if(document[hidden]) {
|
||||
pageIsVisible = false;
|
||||
} else {
|
||||
pageIsVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Add event listener only for supported browsers
|
||||
if(typeof document.addEventListener !== "undefined" && typeof document[hidden] !== "undefined") {
|
||||
// Handle page visibility change
|
||||
document.addEventListener(visibilityChange, handleVisibilityChange, false);
|
||||
}
|
||||
|
||||
/***
|
||||
GENERAL FUNCTIONS
|
||||
***/
|
||||
@@ -112,11 +58,11 @@ function convertHTMLtoText(htmltxt) {
|
||||
// Function to re-write 0:09:21=>9:21, 0:10:10=>10:10, 0:00:30=>0:30
|
||||
function rewriteTime(timeString) {
|
||||
// Remove "0:0" from start
|
||||
if(timeString.substring(0,3) == '0:0') {
|
||||
if(timeString.substring(0,3) === '0:0') {
|
||||
timeString = timeString.substring(3)
|
||||
}
|
||||
// Remove "0:" from start
|
||||
else if(timeString.substring(0,2) == '0:') {
|
||||
else if(timeString.substring(0,2) === '0:') {
|
||||
timeString = timeString.substring(2)
|
||||
}
|
||||
return timeString
|
||||
@@ -125,13 +71,13 @@ function rewriteTime(timeString) {
|
||||
// How to display the date-time?
|
||||
function displayDateTime(inDate, outFormat, inFormat) {
|
||||
// What input?
|
||||
if(inDate == '') {
|
||||
if(inDate === '') {
|
||||
var theMoment = moment()
|
||||
} else {
|
||||
var theMoment = moment.utc(inDate, inFormat)
|
||||
}
|
||||
// Special format or regular format?
|
||||
if(outFormat == 'fromNow') {
|
||||
if(outFormat === 'fromNow') {
|
||||
return theMoment.fromNow()
|
||||
} else {
|
||||
return theMoment.local().format(outFormat)
|
||||
@@ -209,7 +155,7 @@ function setCheckAllState(checkSelector, rangeSelector) {
|
||||
var nrChecks = allChecks.filter(":checked");
|
||||
if(nrChecks.length === 0) {
|
||||
$(checkSelector).prop({'checked': false, 'indeterminate': false})
|
||||
} else if(nrChecks.length == allChecks.length) {
|
||||
} else if(nrChecks.length === allChecks.length) {
|
||||
$(checkSelector).prop({'checked': true, 'indeterminate': false})
|
||||
} else {
|
||||
$(checkSelector).prop({'checked': false, 'indeterminate': true})
|
||||
@@ -264,18 +210,13 @@ function showNotification(notiName, notiTimeout, fileCounter) {
|
||||
// Remove after timeout
|
||||
if(notiTimeout) {
|
||||
setTimeout(function() {
|
||||
hideNotification(true);
|
||||
hideNotification();
|
||||
}, notiTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
// Hide notification
|
||||
function hideNotification(fadeItOut) {
|
||||
// Hide the box with or without effect
|
||||
if(fadeItOut) {
|
||||
$('.main-notification-box').fadeOut()
|
||||
} else {
|
||||
$('.main-notification-box').hide()
|
||||
}
|
||||
|
||||
function hideNotification() {
|
||||
// Hide the box with effect
|
||||
$('.main-notification-box').fadeOut()
|
||||
}
|
||||
@@ -4,6 +4,9 @@ function Fileslisting(parent) {
|
||||
self.parent = parent;
|
||||
self.fileItems = ko.observableArray([]);
|
||||
|
||||
// Prevent flash of unstyled content when deleting items
|
||||
self.fileItems.extend({ rateLimit: 50 })
|
||||
|
||||
// Need to reserve these names to be overwritten
|
||||
self.filelist_name = ko.observable();
|
||||
self.filelist_password = ko.observable();
|
||||
@@ -30,42 +33,17 @@ function Fileslisting(parent) {
|
||||
$('#modal-item-files').modal('show');
|
||||
|
||||
// Stop updating on closing of the modal
|
||||
$('#modal-item-files').on('hidden.bs.modal', function() {
|
||||
$('#modal-item-files').on('hidden.bs.modal', function () {
|
||||
self.removeUpdate();
|
||||
})
|
||||
}
|
||||
|
||||
// Move to top and bottom buttons
|
||||
self.moveButton = function (item,event) {
|
||||
var targetRow, sourceRow, tbody;
|
||||
sourceRow = $(event.currentTarget).parents("tr").filter(":first");
|
||||
tbody = sourceRow.parents("tbody").filter(":first");
|
||||
ko.utils.domData.set(sourceRow[0], "ko_sourceIndex", ko.utils.arrayIndexOf(sourceRow.parent().children(), sourceRow[0]));
|
||||
sourceRow = sourceRow.detach();
|
||||
if ($(event.currentTarget).is(".buttonMoveToTop")) {
|
||||
// we are moving to the top
|
||||
targetRow = tbody.children(".files-done").filter(":last");
|
||||
} else {
|
||||
//we are moving to the bottom
|
||||
targetRow = tbody.children(".files-sortable").filter(":last");
|
||||
}
|
||||
if(targetRow.length < 1 ){
|
||||
// we found an edge case and need to do something special
|
||||
targetRow = tbody.children(".files-sortable").filter(":first");
|
||||
sourceRow.insertBefore(targetRow[0]);
|
||||
} else {
|
||||
sourceRow.insertAfter($(targetRow[0]));
|
||||
}
|
||||
tbody.sortable('option', 'update').call(tbody[0],null, { item: sourceRow });
|
||||
};
|
||||
|
||||
// Trigger update
|
||||
self.triggerUpdate = function() {
|
||||
// Call API
|
||||
callAPI({
|
||||
mode: 'get_files',
|
||||
value: self.currentItem.id,
|
||||
limit: 5
|
||||
value: self.currentItem.id
|
||||
}).then(function(response) {
|
||||
// When there's no files left we close the modal and the update will be stopped
|
||||
// For example when the job has finished downloading
|
||||
@@ -79,7 +57,7 @@ function Fileslisting(parent) {
|
||||
$.each(response.files, function(index, slot) {
|
||||
// Existing or updating?
|
||||
var existingItem = ko.utils.arrayFirst(self.fileItems(), function(i) {
|
||||
return i.nzf_id() == slot.nzf_id;
|
||||
return i.nzf_id() === slot.nzf_id;
|
||||
});
|
||||
|
||||
if(existingItem) {
|
||||
@@ -98,7 +76,7 @@ function Fileslisting(parent) {
|
||||
}
|
||||
|
||||
// Check if we show/hide completed
|
||||
if(localStorageGetItem('showCompletedFiles') == 'No') {
|
||||
if(localStorageGetItem('showCompletedFiles') === 'No') {
|
||||
$('.item-files-table tr.files-done').hide();
|
||||
$('#filelist-showcompleted').removeClass('hover-button')
|
||||
}
|
||||
@@ -124,39 +102,57 @@ function Fileslisting(parent) {
|
||||
self.move = function(event) {
|
||||
// How much did we move?
|
||||
var nrMoves = event.sourceIndex - event.targetIndex;
|
||||
var direction = (nrMoves > 0 ? 'Up' : 'Down')
|
||||
var direction = (nrMoves > 0 ? 'up' : 'down')
|
||||
|
||||
// We have to create the data-structure before, to be able to use the name as a key
|
||||
var dataToSend = {};
|
||||
dataToSend[event.item.nzf_id()] = 'on';
|
||||
dataToSend['apikey'] = apiKey;
|
||||
dataToSend['action_key'] = direction;
|
||||
dataToSend['action_size'] = Math.abs(nrMoves);
|
||||
callAPI({
|
||||
mode: 'move_nzf_bulk',
|
||||
name: direction,
|
||||
value: self.currentItem.id,
|
||||
nzf_ids: event.item.nzf_id(),
|
||||
size: Math.abs(nrMoves)
|
||||
}).then(function() {
|
||||
// Refresh all the files
|
||||
self.loadFiles(self.currentItem)
|
||||
})
|
||||
};
|
||||
|
||||
// Activate with this weird URL "API"
|
||||
callSpecialAPI("./nzb/" + self.currentItem.id + "/bulk_operation/", dataToSend)
|
||||
// Move to top and bottom buttons
|
||||
self.moveButton = function (item, event) {
|
||||
// Up or down?
|
||||
var direction = "bottom"
|
||||
if ($(event.currentTarget).is(".buttonMoveToTop")) {
|
||||
// we are moving to the top
|
||||
direction = "top"
|
||||
}
|
||||
|
||||
callAPI({
|
||||
mode: 'move_nzf_bulk',
|
||||
name: direction,
|
||||
value: self.currentItem.id,
|
||||
nzf_ids: item.nzf_id()
|
||||
}).then(function() {
|
||||
// Refresh all the files
|
||||
self.loadFiles(self.currentItem)
|
||||
})
|
||||
};
|
||||
|
||||
// Remove selected files
|
||||
self.removeSelectedFiles = function() {
|
||||
// We have to create the data-structure before, to be able to use the name as a key
|
||||
var dataToSend = {};
|
||||
dataToSend['apikey'] = apiKey;
|
||||
dataToSend['action_key'] = 'Delete';
|
||||
|
||||
// Get all selected ones
|
||||
var nzfIds = []
|
||||
$('.item-files-table input:checked:not(:disabled)').each(function() {
|
||||
// Add this item
|
||||
dataToSend[$(this).prop('name')] = 'on';
|
||||
nzfIds.push($(this).prop('name'))
|
||||
})
|
||||
|
||||
// Activate with this weird URL "API"
|
||||
callSpecialAPI("./nzb/" + self.currentItem.id + "/bulk_operation/", dataToSend).then(function() {
|
||||
// Fade it out
|
||||
$('.item-files-table input:checked:not(:disabled)').parents('tr').fadeOut(fadeOnDeleteDuration, function() {
|
||||
// Set state of the check-all
|
||||
setCheckAllState('#modal-item-files .multioperations-selector input[type="checkbox"]', '#modal-item-files .files-sortable input')
|
||||
})
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'delete_nzf',
|
||||
value: self.currentItem.id,
|
||||
value2: nzfIds.join()
|
||||
}).then(function() {
|
||||
// Refresh all the files
|
||||
self.loadFiles(self.currentItem)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -221,8 +217,8 @@ function FileslistingModel(parent, data) {
|
||||
self.nzf_id = ko.observable(data.nzf_id);
|
||||
self.file_age = ko.observable(data.age);
|
||||
self.mb = ko.observable(data.mb);
|
||||
self.canselect = ko.observable(data.status != "finished" && data.status != "queued");
|
||||
self.isdone = ko.observable(data.status == "finished");
|
||||
self.canselect = ko.observable(data.status !== "finished" && data.status !== "queued");
|
||||
self.isdone = ko.observable(data.status === "finished");
|
||||
self.percentage = ko.observable(self.isdone() ? fixPercentages(100) : fixPercentages((100 - (data.mbleft / data.mb * 100)).toFixed(0)));
|
||||
|
||||
// Update internally
|
||||
@@ -231,8 +227,8 @@ function FileslistingModel(parent, data) {
|
||||
self.nzf_id(data.nzf_id)
|
||||
self.file_age(data.age)
|
||||
self.mb(data.mb)
|
||||
self.canselect(data.status != "finished" && data.status != "queued")
|
||||
self.isdone(data.status == "finished")
|
||||
self.canselect(data.status !== "finished" && data.status !== "queued")
|
||||
self.isdone(data.status === "finished")
|
||||
// Data is given in MB, would always show 0% for small files even if completed
|
||||
self.percentage(self.isdone() ? fixPercentages(100) : fixPercentages((100 - (data.mbleft / data.mb * 100)).toFixed(0)))
|
||||
}
|
||||
@@ -270,7 +266,7 @@ function paginationModel(parent) {
|
||||
// Return object for adding
|
||||
return {
|
||||
page: pageNr,
|
||||
isCurrent: pageNr == self.currentPage(),
|
||||
isCurrent: pageNr === self.currentPage(),
|
||||
isDots: false,
|
||||
onclick: function(data) {
|
||||
self.moveToPage(data.page);
|
||||
@@ -298,7 +294,7 @@ function paginationModel(parent) {
|
||||
self.nrPages(1)
|
||||
self.currentStart(0);
|
||||
|
||||
// Are we on next page?
|
||||
// Are we on next page? Bad!
|
||||
if(self.currentPage() > 1) {
|
||||
// Force full update
|
||||
parent.parent.refresh(true);
|
||||
@@ -306,9 +302,6 @@ function paginationModel(parent) {
|
||||
|
||||
// Move to current page
|
||||
self.currentPage(1);
|
||||
|
||||
// Force full update
|
||||
parent.parent.refresh(true);
|
||||
} else {
|
||||
// Calculate number of pages needed
|
||||
var newNrPages = Math.ceil(parent.totalItems() / parent.paginationLimit())
|
||||
@@ -363,7 +356,7 @@ function paginationModel(parent) {
|
||||
}
|
||||
|
||||
// Change of number of pages?
|
||||
if(newNrPages != self.nrPages()) {
|
||||
if(newNrPages !== self.nrPages()) {
|
||||
// Update
|
||||
self.nrPages(newNrPages);
|
||||
}
|
||||
|
||||
@@ -8,12 +8,18 @@ function HistoryListModel(parent) {
|
||||
// Variables
|
||||
self.lastUpdate = 0;
|
||||
self.historyItems = ko.observableArray([])
|
||||
self.showFailed = ko.observable(false);
|
||||
self.showFailed = ko.observable(false).extend({ persist: 'historyShowFailed' });
|
||||
self.showArchive = ko.observable(false).extend({ persist: 'historyShowArchive' });
|
||||
self.permanentlyDelete = ko.observable(false).extend({ persist: 'permanentlyDelete' });
|
||||
self.isLoading = ko.observable(false).extend({ rateLimit: 100 });
|
||||
self.searchTerm = ko.observable('').extend({ rateLimit: { timeout: 200, method: "notifyWhenChangesStop" } });
|
||||
self.searchTerm = ko.observable('').extend({ rateLimit: { timeout: 400, method: "notifyWhenChangesStop" } });
|
||||
self.paginationLimit = ko.observable(10).extend({ persist: 'historyPaginationLimit' });
|
||||
self.totalItems = ko.observable(0);
|
||||
self.deleteItems = ko.observableArray([]);
|
||||
self.ppItems = ko.observable(0);
|
||||
self.pagination = new paginationModel(self);
|
||||
self.isMultiEditing = ko.observable(false).extend({ persist: 'historyIsMultiEditing' });
|
||||
self.multiEditItems = ko.observableArray([]);
|
||||
|
||||
// Download history info
|
||||
self.downloadedToday = ko.observable();
|
||||
@@ -40,7 +46,7 @@ function HistoryListModel(parent) {
|
||||
var newItems = [];
|
||||
$.each(data.slots, function(index, slot) {
|
||||
var existingItem = ko.utils.arrayFirst(self.historyItems(), function(i) {
|
||||
return i.historyStatus.nzo_id() == slot.nzo_id;
|
||||
return i.historyStatus.nzo_id() === slot.nzo_id;
|
||||
});
|
||||
// Set index in the results
|
||||
slot.index = index
|
||||
@@ -56,7 +62,7 @@ function HistoryListModel(parent) {
|
||||
});
|
||||
|
||||
// Remove all items
|
||||
if(itemIds.length == self.paginationLimit()) {
|
||||
if(itemIds.length === self.paginationLimit()) {
|
||||
// Replace it, so only 1 Knockout DOM-update!
|
||||
self.historyItems(newItems);
|
||||
newItems = [];
|
||||
@@ -65,7 +71,7 @@ function HistoryListModel(parent) {
|
||||
$.each(itemIds, function() {
|
||||
var id = this.toString();
|
||||
self.historyItems.remove(ko.utils.arrayFirst(self.historyItems(), function(i) {
|
||||
return i.historyStatus.nzo_id() == id;
|
||||
return i.historyStatus.nzo_id() === id;
|
||||
}));
|
||||
});
|
||||
}
|
||||
@@ -79,7 +85,7 @@ function HistoryListModel(parent) {
|
||||
if(self.parent.queue.multiEditItems().length > 0) {
|
||||
$.each(newItems, function() {
|
||||
var currentItem = this;
|
||||
self.parent.queue.multiEditItems.remove(function(inList) { return inList.id == currentItem.nzo_id; })
|
||||
self.parent.queue.multiEditItems.remove(function(inList) { return inList.id === currentItem.id; })
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -93,6 +99,7 @@ function HistoryListModel(parent) {
|
||||
History information
|
||||
***/
|
||||
self.totalItems(data.noofslots);
|
||||
self.ppItems(data.ppslots)
|
||||
self.downloadedToday(data.day_size);
|
||||
self.downloadedWeek(data.week_size);
|
||||
self.downloadedMonth(data.month_size);
|
||||
@@ -110,20 +117,44 @@ function HistoryListModel(parent) {
|
||||
value: newValue
|
||||
})
|
||||
}
|
||||
// Update pagination and counters
|
||||
self.parent.refresh(true)
|
||||
});
|
||||
|
||||
self.triggerRemoveDownload = function(items) {
|
||||
// Show and fill modal
|
||||
self.deleteItems.removeAll()
|
||||
|
||||
// Single or multiple items?
|
||||
if(items.length) {
|
||||
ko.utils.arrayPushAll(self.deleteItems, items)
|
||||
} else {
|
||||
self.deleteItems.push(items)
|
||||
}
|
||||
|
||||
// Show modal or delete right away
|
||||
if(self.parent.confirmDeleteHistory()) {
|
||||
// Open modal if desired
|
||||
$('#modal-delete-history-job').modal("show")
|
||||
} else {
|
||||
// Otherwise just submit right away
|
||||
$('#modal-delete-history-job form').submit()
|
||||
}
|
||||
}
|
||||
|
||||
// Retry a job
|
||||
self.retryJob = function(form) {
|
||||
// Adding a extra retry file happens through this special function
|
||||
var data = new FormData();
|
||||
data.append("mode", "retry");
|
||||
data.append("nzbfile", $(form.nzbFile)[0].files[0]);
|
||||
data.append("job", $('#modal-retry-job input[name="retry_job_id"]').val());
|
||||
data.append("value", $('#modal-retry-job input[name="retry_job_id"]').val());
|
||||
data.append("password", $('#retry_job_password').val());
|
||||
data.append("apikey", apiKey);
|
||||
|
||||
// Add
|
||||
$.ajax({
|
||||
url: "./retry_pp",
|
||||
url: "./api",
|
||||
type: "POST",
|
||||
cache: false,
|
||||
processData: false,
|
||||
@@ -138,28 +169,28 @@ function HistoryListModel(parent) {
|
||||
form.reset()
|
||||
}
|
||||
|
||||
// Searching in history (rate-limited in decleration)
|
||||
// Searching in history (rate-limited in declaration)
|
||||
self.searchTerm.subscribe(function() {
|
||||
// Make sure we refresh
|
||||
self.lastUpdate = 0
|
||||
self.parent.refresh();
|
||||
// Go back to page 1
|
||||
if(self.pagination.currentPage() != 1) {
|
||||
if(self.pagination.currentPage() !== 1) {
|
||||
// This forces a refresh
|
||||
self.pagination.moveToPage(1);
|
||||
} else {
|
||||
// Make sure we refresh
|
||||
self.parent.refresh(true);
|
||||
}
|
||||
})
|
||||
|
||||
// Clear searchterm
|
||||
self.clearSearchTerm = function(data, event) {
|
||||
// Was it escape key or click?
|
||||
if(event.type == 'mousedown' || (event.keyCode && event.keyCode == 27)) {
|
||||
if(event.type === 'mousedown' || (event.keyCode && event.keyCode === 27)) {
|
||||
// Set the loader so it doesn't flicker and then switch
|
||||
self.isLoading(true)
|
||||
self.searchTerm('');
|
||||
self.parent.refresh()
|
||||
}
|
||||
// Was it click and the field is empty? Then we focus on the field
|
||||
if(event.type == 'mousedown' && self.searchTerm() == '') {
|
||||
if(event.type === 'mousedown' && self.searchTerm() === '') {
|
||||
$(event.target).parents('.search-box').find('input[type="text"]').focus()
|
||||
return;
|
||||
}
|
||||
@@ -169,10 +200,17 @@ function HistoryListModel(parent) {
|
||||
|
||||
// Toggle showing failed
|
||||
self.toggleShowFailed = function(data, event) {
|
||||
// Set the loader so it doesn't flicker and then switch
|
||||
self.isLoading(true)
|
||||
self.showFailed(!self.showFailed())
|
||||
// Forde hide tooltip so it doesn't linger
|
||||
// Force hide tooltip so it doesn't linger
|
||||
$('#history-options a').tooltip('hide')
|
||||
// Force refresh
|
||||
self.parent.refresh(true)
|
||||
}
|
||||
|
||||
// Toggle showing archive
|
||||
self.toggleShowArchive = function(data, event) {
|
||||
self.showArchive(!self.showArchive())
|
||||
// Force hide tooltip so it doesn't linger
|
||||
$('#history-options a').tooltip('hide')
|
||||
// Force refresh
|
||||
self.parent.refresh(true)
|
||||
@@ -194,36 +232,34 @@ function HistoryListModel(parent) {
|
||||
|
||||
// Empty history options
|
||||
self.emptyHistory = function(data, event) {
|
||||
// Make sure no flickering
|
||||
self.isLoading(true)
|
||||
|
||||
// What event?
|
||||
var whatToRemove = $(event.target).data('action');
|
||||
var skipArchive = $('#modal-purge-history input[type="checkbox"]').prop("checked")
|
||||
var del_files, value;
|
||||
|
||||
// Purge failed
|
||||
if(whatToRemove == 'history-purge-failed') {
|
||||
if(whatToRemove === 'history-purge-failed') {
|
||||
del_files = 0;
|
||||
value = 'failed';
|
||||
}
|
||||
// Also remove files
|
||||
if(whatToRemove == 'history-purgeremove-failed') {
|
||||
if(whatToRemove === 'history-purgeremove-failed') {
|
||||
del_files = 1;
|
||||
value = 'failed';
|
||||
}
|
||||
// Remove completed
|
||||
if(whatToRemove == 'history-purge-completed') {
|
||||
if(whatToRemove === 'history-purge-completed') {
|
||||
del_files = 0;
|
||||
value = 'completed';
|
||||
}
|
||||
// Remove the ones on this page
|
||||
if(whatToRemove == 'history-purge-page') {
|
||||
if(whatToRemove === 'history-purge-page') {
|
||||
// List all the ID's
|
||||
var strIDs = '';
|
||||
$.each(self.historyItems(), function(index) {
|
||||
// Only append when it's a download that can be deleted
|
||||
if(!this.processingDownload() && !this.processingWaiting()) {
|
||||
strIDs = strIDs + this.nzo_id + ',';
|
||||
strIDs = strIDs + this.id + ',';
|
||||
}
|
||||
})
|
||||
// Send the command
|
||||
@@ -231,6 +267,7 @@ function HistoryListModel(parent) {
|
||||
mode: 'history',
|
||||
name: 'delete',
|
||||
del_files: 1,
|
||||
archive: (!skipArchive) * 1,
|
||||
value: strIDs
|
||||
}).then(function() {
|
||||
// Clear search, refresh and hide
|
||||
@@ -245,13 +282,197 @@ function HistoryListModel(parent) {
|
||||
callAPI({
|
||||
mode: 'history',
|
||||
name: 'delete',
|
||||
value: value,
|
||||
del_files: del_files
|
||||
del_files: del_files,
|
||||
archive: (!skipArchive) * 1,
|
||||
value: value
|
||||
}).then(function() {
|
||||
self.parent.refresh();
|
||||
$("#modal-purge-history").modal('hide');
|
||||
});
|
||||
};
|
||||
|
||||
// Show the input checkbox
|
||||
self.showMultiEdit = function() {
|
||||
self.isMultiEditing(!self.isMultiEditing())
|
||||
self.multiEditItems.removeAll();
|
||||
$('.history-table input[name="multiedit"], #multiedit-checkall-history').prop({'checked': false, 'indeterminate': false})
|
||||
}
|
||||
|
||||
// Add to the list
|
||||
self.addMultiEdit = function(item, event) {
|
||||
// Is it a shift-click?
|
||||
if(event.shiftKey) {
|
||||
checkShiftRange('.history-table input[name="multiedit"]');
|
||||
}
|
||||
|
||||
// Add or remove from the list?
|
||||
if(event.currentTarget.checked) {
|
||||
// Add item
|
||||
self.multiEditItems.push(item);
|
||||
} else {
|
||||
// Go over them all to know which one to remove
|
||||
self.multiEditItems.remove(function(inList) { return inList.id == item.id; })
|
||||
}
|
||||
|
||||
// Update check-all buton state
|
||||
setCheckAllState('#multiedit-checkall-history', '.history-table input[name="multiedit"]')
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check all
|
||||
self.checkAllJobs = function(item, event) {
|
||||
// Get which ones we care about
|
||||
var allChecks = $('.history-table input[name="multiedit"]').filter(':not(:disabled):visible');
|
||||
|
||||
// We need to re-evaltuate the state of this check-all
|
||||
// Otherwise the 'inderterminate' will be overwritten by the click event!
|
||||
setCheckAllState('#multiedit-checkall-history', '.history-table input[name="multiedit"]')
|
||||
|
||||
// Now we can check what happend
|
||||
// For when some are checked, or all are checked (but not partly)
|
||||
if(event.target.indeterminate || (event.target.checked && !event.target.indeterminate)) {
|
||||
var allActive = allChecks.filter(":checked")
|
||||
// First remove the from the list
|
||||
if(allActive.length == self.multiEditItems().length) {
|
||||
// Just remove all
|
||||
self.multiEditItems.removeAll();
|
||||
// Remove the check
|
||||
allActive.prop('checked', false)
|
||||
} else {
|
||||
// Remove them seperate
|
||||
allActive.each(function() {
|
||||
// Go over them all to know which one to remove
|
||||
var item = ko.dataFor(this)
|
||||
self.multiEditItems.remove(function(inList) { return inList.id == item.id; })
|
||||
// Remove the check of this one
|
||||
this.checked = false;
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// None are checked, so check and add them all
|
||||
allChecks.prop('checked', true)
|
||||
allChecks.each(function() { self.multiEditItems.push(ko.dataFor(this)) })
|
||||
event.target.checked = true
|
||||
}
|
||||
// Set state of all the check-all's
|
||||
setCheckAllState('#multiedit-checkall-history', '.history-table input[name="multiedit"]')
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove downloads from history
|
||||
self.removeDownloads = function(form) {
|
||||
// Hide modal and show notification
|
||||
$('#modal-delete-history-job').modal("hide")
|
||||
showNotification('.main-notification-box-removing')
|
||||
|
||||
var strIDsPP = '';
|
||||
var strIDsHistory = '';
|
||||
$.each(self.deleteItems(), function(index) {
|
||||
// Split in jobs that need post-processing aborted, and jobs that need to be deleted
|
||||
if(this.processingDownload() === 2) {
|
||||
strIDsPP = strIDsPP + this.id + ',';
|
||||
// These items should not be listed in the deletedItems later on
|
||||
// as active post-processing aren't removed from the history output
|
||||
self.deleteItems.remove(this)
|
||||
} else {
|
||||
strIDsHistory = strIDsHistory + this.id + ',';
|
||||
}
|
||||
})
|
||||
|
||||
// Trigger post-processing aborting
|
||||
if(strIDsPP !== "") {
|
||||
callAPI({
|
||||
mode: 'cancel_pp',
|
||||
value: strIDsPP
|
||||
}).then(function(response) {
|
||||
// Only hide and refresh
|
||||
self.parent.refresh();
|
||||
hideNotification()
|
||||
});
|
||||
}
|
||||
if(strIDsHistory !== "") {
|
||||
var skipArchive = $('#modal-delete-history-job input[type="checkbox"]').prop("checked")
|
||||
|
||||
// Permanently delete if we are on the Archive page
|
||||
if(self.showArchive()) skipArchive = true
|
||||
|
||||
callAPI({
|
||||
mode: 'history',
|
||||
name: 'delete',
|
||||
del_files: 1,
|
||||
archive: (!skipArchive) * 1,
|
||||
value: strIDsHistory
|
||||
}).then(function(response) {
|
||||
self.historyItems.removeAll(self.deleteItems());
|
||||
self.multiEditItems.removeAll(self.deleteItems())
|
||||
self.parent.refresh();
|
||||
hideNotification()
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Delete all selected
|
||||
self.doMultiDelete = function() {
|
||||
// Anything selected?
|
||||
if(self.multiEditItems().length < 1) return;
|
||||
|
||||
// Trigger modal
|
||||
self.triggerRemoveDownload(self.multiEditItems())
|
||||
}
|
||||
|
||||
// Mark jobs as completed
|
||||
self.markAsCompleted = function(items) {
|
||||
// Confirm
|
||||
if(!confirm(glitterTranslate.markComplete)) {
|
||||
return
|
||||
}
|
||||
// Single or multiple items?
|
||||
var strIDs = '';
|
||||
if(items.length) {
|
||||
$.each(items, function(index) {
|
||||
strIDs = strIDs + this.id + ',';
|
||||
})
|
||||
} else {
|
||||
strIDs = items.id
|
||||
}
|
||||
|
||||
// Send the API call
|
||||
callAPI({
|
||||
mode: 'history',
|
||||
name: 'mark_as_completed',
|
||||
value: strIDs
|
||||
}).then(function(response) {
|
||||
// Force refresh to update the UI
|
||||
self.parent.refresh(true);
|
||||
});
|
||||
}
|
||||
|
||||
// Mark all selected as completed
|
||||
self.doMultiMarkCompleted = function() {
|
||||
// Anything selected?
|
||||
if(self.multiEditItems().length < 1) return;
|
||||
|
||||
// Mark them
|
||||
self.markAsCompleted(self.multiEditItems());
|
||||
}
|
||||
|
||||
// Focus on the confirm button
|
||||
$('#modal-delete-history-job').on("shown.bs.modal", function() {
|
||||
$('#modal-delete-history-job .btn[type="submit"]').focus()
|
||||
})
|
||||
|
||||
// On change of page we need to check all those that were in the list!
|
||||
self.historyItems.subscribe(function() {
|
||||
// We need to wait until the unit is actually finished rendering
|
||||
setTimeout(function() {
|
||||
$.each(self.multiEditItems(), function(index) {
|
||||
$('#multiedit_' + this.id).prop('checked', true);
|
||||
})
|
||||
|
||||
// Update check-all buton state
|
||||
setCheckAllState('#multiedit-checkall-history', '.history-table input[name="multiedit"]')
|
||||
}, 100)
|
||||
}, null, "arrayChange")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -265,7 +486,7 @@ function HistoryModel(parent, data) {
|
||||
// If we update the full set every time it uses lot of CPU
|
||||
// The Status/Actionline/scriptline/completed we do update every time
|
||||
// When clicked on the more-info button we load the rest again
|
||||
self.nzo_id = data.nzo_id;
|
||||
self.id = data.nzo_id;
|
||||
self.index = data.index;
|
||||
self.updateAllHistory = false;
|
||||
self.hasDropdown = ko.observable(false);
|
||||
@@ -302,14 +523,14 @@ function HistoryModel(parent, data) {
|
||||
|
||||
// Waiting?
|
||||
self.processingWaiting = ko.pureComputed(function() {
|
||||
return(self.status() == 'Queued')
|
||||
return(self.status() === 'Queued')
|
||||
})
|
||||
|
||||
// Processing or done?
|
||||
self.processingDownload = ko.pureComputed(function() {
|
||||
var status = self.status();
|
||||
// When we can cancel
|
||||
if (status === 'Extracting' || status === 'Verifying' || status == 'Repairing' || status === 'Running') {
|
||||
if (status === 'Extracting' || status === 'Verifying' || status === 'Repairing' || status === 'Running') {
|
||||
return 2
|
||||
}
|
||||
// These cannot be cancelled
|
||||
@@ -333,17 +554,17 @@ function HistoryModel(parent, data) {
|
||||
return self.script_line();
|
||||
});
|
||||
|
||||
// Extra history column
|
||||
self.extraText = ko.pureComputed(function() {
|
||||
// Extra history columns
|
||||
self.showColumn = function(param) {
|
||||
// Picked anything?
|
||||
switch(self.parent.parent.extraHistoryColumn()) {
|
||||
switch(param) {
|
||||
case 'speed':
|
||||
// Anything to calculate?
|
||||
if(self.historyStatus.bytes() > 0 && self.historyStatus.download_time() > 0) {
|
||||
try {
|
||||
// Extract the Download section
|
||||
var downloadLog = ko.utils.arrayFirst(self.historyStatus.stage_log(), function(item) {
|
||||
return item.name() == 'Download'
|
||||
return item.name() === 'Download'
|
||||
});
|
||||
// Extract the speed
|
||||
return downloadLog.actions()[0].match(/(\S*\s\S+)(?=<br\/>)/)[0]
|
||||
@@ -352,20 +573,25 @@ function HistoryModel(parent, data) {
|
||||
return;
|
||||
case 'category':
|
||||
// Exception for *
|
||||
if(self.historyStatus.category() == "*")
|
||||
if(self.historyStatus.category() === "*")
|
||||
return glitterTranslate.defaultText
|
||||
return self.historyStatus.category();
|
||||
case 'size':
|
||||
return self.historyStatus.size();
|
||||
}
|
||||
return;
|
||||
})
|
||||
};
|
||||
|
||||
// Format completion time
|
||||
self.completedOn = ko.pureComputed(function() {
|
||||
return displayDateTime(self.completed(), parent.parent.dateFormat(), 'X')
|
||||
});
|
||||
|
||||
// Format time added
|
||||
self.timeAdded = ko.pureComputed(function() {
|
||||
return displayDateTime(self.historyStatus.time_added(), parent.parent.dateFormat(), 'X')
|
||||
});
|
||||
|
||||
// Subscribe to retryEvent so we can load the password
|
||||
self.canRetry.subscribe(function() {
|
||||
self.updateAllHistory = true;
|
||||
@@ -374,13 +600,18 @@ function HistoryModel(parent, data) {
|
||||
// Re-try button
|
||||
self.retry = function() {
|
||||
// Set JOB-id
|
||||
$('#modal-retry-job input[name="retry_job_id"]').val(self.nzo_id)
|
||||
$('#modal-retry-job input[name="retry_job_id"]').val(self.id)
|
||||
// Set password
|
||||
$('#retry_job_password').val(self.historyStatus.password())
|
||||
// Open modal
|
||||
$('#modal-retry-job').modal("show")
|
||||
};
|
||||
|
||||
// Mark as completed button
|
||||
self.markAsCompleted = function() {
|
||||
parent.markAsCompleted(self);
|
||||
};
|
||||
|
||||
// Update information only on click
|
||||
self.updateAllHistoryInfo = function(data, event) {
|
||||
// Show
|
||||
@@ -417,137 +648,4 @@ function HistoryModel(parent, data) {
|
||||
return false;
|
||||
})
|
||||
}
|
||||
|
||||
// Delete button
|
||||
self.deleteSlot = function(item, event) {
|
||||
// Confirm?
|
||||
if(!self.parent.parent.confirmDeleteHistory() || confirm(glitterTranslate.removeDow1)) {
|
||||
// Are we still processing and it can be stopped?
|
||||
if(item.processingDownload() == 2) {
|
||||
callAPI({
|
||||
mode: 'cancel_pp',
|
||||
value: self.nzo_id
|
||||
})
|
||||
// All we can do is wait
|
||||
} else {
|
||||
// Delete the item
|
||||
callAPI({
|
||||
mode: 'history',
|
||||
name: 'delete',
|
||||
del_files: 1,
|
||||
value: self.nzo_id
|
||||
}).then(function(response) {
|
||||
if(response.status) {
|
||||
// Fade and remove
|
||||
$(event.currentTarget).parent().parent().fadeOut(fadeOnDeleteDuration, function() {
|
||||
// Make sure no flickering (if there are more items left) and then remove
|
||||
self.parent.isLoading(self.parent.totalItems() > 1)
|
||||
self.parent.historyItems.remove(self);
|
||||
self.parent.parent.refresh();
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// User voting
|
||||
self.setUserVote = function(item, event) {
|
||||
// Send vote
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'rating',
|
||||
type: 'vote',
|
||||
setting: $(event.target).val(),
|
||||
value: self.nzo_id
|
||||
}).then(function(response) {
|
||||
// Update all info
|
||||
self.updateAllHistory = true;
|
||||
self.parent.parent.refresh(true)
|
||||
})
|
||||
}
|
||||
|
||||
// User rating
|
||||
self.setUserRating = function(item, event) {
|
||||
// Audio or video
|
||||
var changeWhat = 'audio';
|
||||
if($(event.target).attr('name') == 'ratings-video') {
|
||||
changeWhat = 'video';
|
||||
}
|
||||
|
||||
// Only on user-event, not the auto-fired ones
|
||||
if(!event.originalEvent) return;
|
||||
|
||||
// Send vote
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'rating',
|
||||
type: changeWhat,
|
||||
setting: $(event.target).val(),
|
||||
value: self.nzo_id
|
||||
}).then(function(response) {
|
||||
// Update all info
|
||||
self.updateAllHistory = true;
|
||||
self.parent.parent.refresh(true)
|
||||
})
|
||||
}
|
||||
|
||||
// User comment
|
||||
self.setUserReport = function(form) {
|
||||
// What are we reporting?
|
||||
var userReport = $(form).find('input[name="rating_flag"]:checked').val();
|
||||
var userDetail = '';
|
||||
|
||||
// Anything selected?
|
||||
if(!userReport) {
|
||||
alert(glitterTranslate.noSelect)
|
||||
return;
|
||||
}
|
||||
|
||||
// Extra info?
|
||||
if(userReport == 'comment') userDetail = $(form).find('input[name="ratings-report-comment"]').val();
|
||||
if(userReport == 'other') userDetail = $(form).find('input[name="ratings-report-other"]').val();
|
||||
|
||||
// Exception for servers
|
||||
if(userReport == 'expired') {
|
||||
// Which server?
|
||||
userDetail = $(form).find('select[name="ratings-report-expired-server"]').val();
|
||||
|
||||
// All?
|
||||
if(userDetail == "") {
|
||||
// Loop over all servers
|
||||
$.each(parent.parent.servers, function(index, server) {
|
||||
// Set timeout because simultanious requests don't work (yet)
|
||||
setTimeout(function() {
|
||||
submitUserReport(server.name)
|
||||
}, index * 1500)
|
||||
})
|
||||
|
||||
} else {
|
||||
// Just the one server
|
||||
submitUserReport(userDetail)
|
||||
}
|
||||
} else {
|
||||
submitUserReport(userDetail)
|
||||
}
|
||||
|
||||
// After all, close it
|
||||
form.reset();
|
||||
$(form).parent().parent().dropdown('toggle');
|
||||
alert(glitterTranslate.sendThanks)
|
||||
|
||||
function submitUserReport(theDetail) {
|
||||
// Send note
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'rating',
|
||||
type: 'flag',
|
||||
setting: userReport,
|
||||
detail: theDetail,
|
||||
value: self.nzo_id
|
||||
})
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,6 @@ function QueueListModel(parent) {
|
||||
var self = this;
|
||||
self.parent = parent;
|
||||
self.dragging = false;
|
||||
self.rawCatList = [];
|
||||
self.rawScriptList = [];
|
||||
|
||||
// Because SABNZB returns the name
|
||||
// But when you want to set Priority you need the number..
|
||||
@@ -34,12 +32,13 @@ function QueueListModel(parent) {
|
||||
// External var's
|
||||
self.queueItems = ko.observableArray([]);
|
||||
self.totalItems = ko.observable(0);
|
||||
self.isMultiEditing = ko.observable(false);
|
||||
self.deleteItems = ko.observableArray([]);
|
||||
self.isMultiEditing = ko.observable(false).extend({ persist: 'queueIsMultiEditing' });
|
||||
self.isLoading = ko.observable(false).extend({ rateLimit: 100 });
|
||||
self.multiEditItems = ko.observableArray([]);
|
||||
self.categoriesList = ko.observableArray([]);
|
||||
self.scriptsList = ko.observableArray([]);
|
||||
self.searchTerm = ko.observable('').extend({ rateLimit: { timeout: 200, method: "notifyWhenChangesStop" } });
|
||||
self.searchTerm = ko.observable('').extend({ rateLimit: { timeout: 400, method: "notifyWhenChangesStop" } });
|
||||
self.paginationLimit = ko.observable(20).extend({ persist: 'queuePaginationLimit' });
|
||||
self.pagination = new paginationModel(self);
|
||||
|
||||
@@ -66,31 +65,6 @@ function QueueListModel(parent) {
|
||||
return i.id;
|
||||
});
|
||||
|
||||
// Did the category-list change?
|
||||
// Otherwise KO will send updates to all <select> for every refresh()
|
||||
if(self.rawCatList != data.categories.toString()) {
|
||||
// Reformat categories
|
||||
self.categoriesList($.map(data.categories, function(cat) {
|
||||
// Default?
|
||||
if(cat == '*') return { catValue: '*', catText: glitterTranslate.defaultText };
|
||||
return { catValue: cat, catText: cat };
|
||||
}))
|
||||
// Update
|
||||
self.rawCatList = data.categories.toString();
|
||||
}
|
||||
|
||||
// Did the script-list change?
|
||||
if(self.rawScriptList != data.scripts.toString()) {
|
||||
// Reformat script-list
|
||||
self.scriptsList($.map(data.scripts, function(script) {
|
||||
// Default?
|
||||
if(script == 'None') return glitterTranslate.noneText;
|
||||
return script;
|
||||
}))
|
||||
// Update
|
||||
self.rawScriptList = data.scripts.toString();
|
||||
}
|
||||
|
||||
// Set limit
|
||||
self.totalItems(data.noofslots);
|
||||
|
||||
@@ -101,7 +75,7 @@ function QueueListModel(parent) {
|
||||
$.each(data.slots, function() {
|
||||
var item = this;
|
||||
var existingItem = ko.utils.arrayFirst(self.queueItems(), function(i) {
|
||||
return i.id == item.nzo_id;
|
||||
return i.id === item.nzo_id;
|
||||
});
|
||||
|
||||
if(existingItem) {
|
||||
@@ -114,7 +88,7 @@ function QueueListModel(parent) {
|
||||
});
|
||||
|
||||
// Remove all items if there's any
|
||||
if(itemIds.length == self.paginationLimit()) {
|
||||
if(itemIds.length === self.paginationLimit()) {
|
||||
// Replace it, so only 1 Knockout DOM-update!
|
||||
self.queueItems(newItems);
|
||||
newItems = [];
|
||||
@@ -123,7 +97,7 @@ function QueueListModel(parent) {
|
||||
$.each(itemIds, function() {
|
||||
var id = this.toString();
|
||||
self.queueItems.remove(ko.utils.arrayFirst(self.queueItems(), function(i) {
|
||||
return i.id == id;
|
||||
return i.id === id;
|
||||
}));
|
||||
});
|
||||
}
|
||||
@@ -174,6 +148,27 @@ function QueueListModel(parent) {
|
||||
|
||||
}
|
||||
|
||||
self.triggerRemoveDownload = function(items) {
|
||||
// Show and fill modal
|
||||
self.deleteItems.removeAll()
|
||||
|
||||
// Single or multiple items?
|
||||
if(items.length) {
|
||||
ko.utils.arrayPushAll(self.deleteItems, items)
|
||||
} else {
|
||||
self.deleteItems.push(items)
|
||||
}
|
||||
|
||||
// Show modal or delete right away
|
||||
if(self.parent.confirmDeleteQueue()) {
|
||||
// Open modal if desired
|
||||
$('#modal-delete-queue-job').modal("show")
|
||||
} else {
|
||||
// Otherwise just submit right away
|
||||
$('#modal-delete-queue-job form').submit()
|
||||
}
|
||||
}
|
||||
|
||||
// Save pagination state
|
||||
self.paginationLimit.subscribe(function(newValue) {
|
||||
// Save in config if global
|
||||
@@ -185,6 +180,8 @@ function QueueListModel(parent) {
|
||||
value: newValue
|
||||
})
|
||||
}
|
||||
// Update pagination and counters
|
||||
self.parent.refresh(true)
|
||||
});
|
||||
|
||||
// Do we show search box. So it doesn't dissapear when nothing is found
|
||||
@@ -194,24 +191,25 @@ function QueueListModel(parent) {
|
||||
|
||||
// Searching in queue (rate-limited in decleration)
|
||||
self.searchTerm.subscribe(function() {
|
||||
// Refresh now
|
||||
self.parent.refresh();
|
||||
// Go back to page 1
|
||||
if(self.pagination.currentPage() != 1) {
|
||||
if(self.pagination.currentPage() !== 1) {
|
||||
// This forces a refresh
|
||||
self.pagination.moveToPage(1);
|
||||
} else {
|
||||
// Refresh now
|
||||
self.parent.refresh();
|
||||
}
|
||||
})
|
||||
|
||||
// Clear searchterm
|
||||
self.clearSearchTerm = function(data, event) {
|
||||
// Was it escape key or click?
|
||||
if(event.type == 'mousedown' || (event.keyCode && event.keyCode == 27)) {
|
||||
if(event.type === 'mousedown' || (event.keyCode && event.keyCode === 27)) {
|
||||
self.isLoading(true)
|
||||
self.searchTerm('');
|
||||
self.parent.refresh()
|
||||
}
|
||||
// Was it click and the field is empty? Then we focus on the field
|
||||
if(event.type == 'mousedown' && self.searchTerm() == '') {
|
||||
if(event.type === 'mousedown' && self.searchTerm() === '') {
|
||||
$(event.target).parents('.search-box').find('input[type="text"]').focus()
|
||||
return;
|
||||
}
|
||||
@@ -226,13 +224,17 @@ function QueueListModel(parent) {
|
||||
// What action?
|
||||
var sort, dir;
|
||||
switch($(event.currentTarget).data('action')) {
|
||||
case 'sortRemainingAsc':
|
||||
sort = 'remaining';
|
||||
dir = 'asc';
|
||||
break;
|
||||
case 'sortAgeAsc':
|
||||
sort = 'avg_age';
|
||||
dir = 'asc';
|
||||
dir = 'desc';
|
||||
break;
|
||||
case 'sortAgeDesc':
|
||||
sort = 'avg_age';
|
||||
dir = 'desc';
|
||||
dir = 'asc';
|
||||
break;
|
||||
case 'sortNameAsc':
|
||||
sort = 'name';
|
||||
@@ -274,7 +276,7 @@ function QueueListModel(parent) {
|
||||
// Reset form and remove all checked ones
|
||||
$form[0].reset();
|
||||
self.multiEditItems.removeAll();
|
||||
$('.delete input[name="multiedit"], #multiedit-checkall').prop({'checked': false, 'indeterminate': false})
|
||||
$('.queue-table input[name="multiedit"], #multiedit-checkall-queue').prop({'checked': false, 'indeterminate': false})
|
||||
|
||||
// Is the multi-edit in view?
|
||||
if(($form.offset().top + $form.outerHeight(true)) > ($(window).scrollTop()+$(window).height())) {
|
||||
@@ -304,7 +306,7 @@ function QueueListModel(parent) {
|
||||
}
|
||||
|
||||
// Update check-all buton state
|
||||
setCheckAllState('#multiedit-checkall', '.queue-table input[name="multiedit"]')
|
||||
setCheckAllState('#multiedit-checkall-queue', '.queue-table input[name="multiedit"]')
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -315,7 +317,7 @@ function QueueListModel(parent) {
|
||||
|
||||
// We need to re-evaltuate the state of this check-all
|
||||
// Otherwise the 'inderterminate' will be overwritten by the click event!
|
||||
setCheckAllState('#multiedit-checkall', '.queue-table input[name="multiedit"]')
|
||||
setCheckAllState('#multiedit-checkall-queue', '.queue-table input[name="multiedit"]')
|
||||
|
||||
// Now we can check what happend
|
||||
// For when some are checked, or all are checked (but not partly)
|
||||
@@ -347,7 +349,7 @@ function QueueListModel(parent) {
|
||||
self.doMultiEditUpdate()
|
||||
}
|
||||
// Set state of all the check-all's
|
||||
setCheckAllState('#multiedit-checkall', '.queue-table input[name="multiedit"]')
|
||||
setCheckAllState('#multiedit-checkall-queue', '.queue-table input[name="multiedit"]')
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -364,93 +366,160 @@ function QueueListModel(parent) {
|
||||
var newStatus = $('.multioperations-selector input[name="multiedit-status"]:checked').val()
|
||||
|
||||
// List all the ID's
|
||||
var strIDs = '';
|
||||
var strIDs = '';
|
||||
$.each(self.multiEditItems(), function(index) {
|
||||
strIDs = strIDs + this.id + ',';
|
||||
})
|
||||
|
||||
// All non-category updates need to only happen after a category update
|
||||
function nonCatUpdates() {
|
||||
if(newScript !== '') {
|
||||
callAPI({
|
||||
mode: 'change_script',
|
||||
value: strIDs,
|
||||
value2: newScript
|
||||
})
|
||||
}
|
||||
if(newPrior !== '') {
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'priority',
|
||||
value: strIDs,
|
||||
value2: newPrior
|
||||
})
|
||||
}
|
||||
if(newProc !== '') {
|
||||
callAPI({
|
||||
mode: 'change_opts',
|
||||
value: strIDs,
|
||||
value2: newProc
|
||||
})
|
||||
}
|
||||
if(newStatus) {
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: newStatus,
|
||||
value: strIDs
|
||||
})
|
||||
}
|
||||
|
||||
// Wat a little and do the refresh
|
||||
// Only if anything changed!
|
||||
if(newStatus || newProc !== '' || newPrior !== '' || newScript !== '' || newCat !== '') {
|
||||
setTimeout(parent.refresh, 100)
|
||||
}
|
||||
}
|
||||
|
||||
// What is changed?
|
||||
if(newCat != '') {
|
||||
if(newCat !== '') {
|
||||
callAPI({
|
||||
mode: 'change_cat',
|
||||
value: strIDs,
|
||||
value2: newCat
|
||||
})
|
||||
}
|
||||
if(newScript != '') {
|
||||
callAPI({
|
||||
mode: 'change_script',
|
||||
value: strIDs,
|
||||
value2: newScript
|
||||
})
|
||||
}
|
||||
if(newPrior != '') {
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'priority',
|
||||
value: strIDs,
|
||||
value2: newPrior
|
||||
})
|
||||
}
|
||||
if(newProc != '') {
|
||||
callAPI({
|
||||
mode: 'change_opts',
|
||||
value: strIDs,
|
||||
value2: newProc
|
||||
})
|
||||
}
|
||||
if(newStatus) {
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: newStatus,
|
||||
value: strIDs
|
||||
})
|
||||
}).then(nonCatUpdates)
|
||||
} else {
|
||||
nonCatUpdates()
|
||||
}
|
||||
|
||||
// Wat a little and do the refresh
|
||||
// Only if anything changed!
|
||||
if(newStatus || newProc != '' || newPrior != '' || newScript != '' || newCat != '') {
|
||||
setTimeout(parent.refresh, 100)
|
||||
}
|
||||
}
|
||||
|
||||
// Selete all selected
|
||||
// Handle mousedown to capture state before change
|
||||
self.handleMultiEditStatusMouseDown = function(item, event) {
|
||||
var clickedValue = $(event.currentTarget).find("input").val();
|
||||
|
||||
// If this radio was already selected (same value as previous), clear it
|
||||
if ($('.multioperations-selector input[name="multiedit-status"]:checked').val() === clickedValue) {
|
||||
// Clear all radio buttons in this group after the click finished
|
||||
// Hacky, but it works
|
||||
setTimeout(function () {
|
||||
$('.multioperations-selector input[name="multiedit-status"]').prop('checked', false);
|
||||
}, 200)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove downloads from queue
|
||||
self.removeDownloads = function(form) {
|
||||
// Hide modal and show notification
|
||||
$('#modal-delete-queue-job').modal("hide")
|
||||
showNotification('.main-notification-box-removing')
|
||||
|
||||
var strIDs = '';
|
||||
$.each(self.deleteItems(), function(index) {
|
||||
strIDs = strIDs + this.id + ',';
|
||||
})
|
||||
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'delete',
|
||||
del_files: 1,
|
||||
value: strIDs
|
||||
}).then(function(response) {
|
||||
self.queueItems.removeAll(self.deleteItems());
|
||||
self.multiEditItems.removeAll(self.deleteItems())
|
||||
self.parent.refresh();
|
||||
hideNotification()
|
||||
});
|
||||
};
|
||||
|
||||
// Delete all selected
|
||||
self.doMultiDelete = function() {
|
||||
// Anything selected?
|
||||
if(self.multiEditItems().length < 1) return;
|
||||
|
||||
// Need confirm
|
||||
if(!self.parent.confirmDeleteQueue() || confirm(glitterTranslate.removeDown)) {
|
||||
// List all the ID's
|
||||
var strIDs = '';
|
||||
$.each(self.multiEditItems(), function(index) {
|
||||
strIDs = strIDs + this.id + ',';
|
||||
})
|
||||
|
||||
// Show notification
|
||||
showNotification('.main-notification-box-removing-multiple', 0, self.multiEditItems().length)
|
||||
|
||||
// Remove
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'delete',
|
||||
del_files: 1,
|
||||
value: strIDs
|
||||
}).then(function(response) {
|
||||
if(response.status) {
|
||||
// Make sure the queue doesnt flicker and then fade-out
|
||||
self.isLoading(true)
|
||||
$('.delete input:checked').parents('tr').fadeOut(fadeOnDeleteDuration)
|
||||
self.parent.refresh()
|
||||
// Empty it
|
||||
self.multiEditItems.removeAll();
|
||||
// Hide notification
|
||||
hideNotification(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
// Trigger modal
|
||||
self.triggerRemoveDownload(self.multiEditItems())
|
||||
}
|
||||
|
||||
// Move all selected to top
|
||||
self.doMultiMoveToTop = function() {
|
||||
// Anything selected?
|
||||
if(self.multiEditItems().length < 1) return;
|
||||
|
||||
// Move each item to the top, starting from the last one in the sorted list
|
||||
var arrayList = self.multiEditItems()
|
||||
var movePromises = [];
|
||||
for(var i = arrayList.length - 1; i >= 0; i--) {
|
||||
movePromises.push(callAPI({
|
||||
mode: "switch",
|
||||
value: arrayList[i].id,
|
||||
value2: 0
|
||||
}));
|
||||
}
|
||||
|
||||
// Wait for all moves to complete then refresh
|
||||
Promise.all(movePromises).then(function() {
|
||||
self.parent.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
// Move all selected to bottom
|
||||
self.doMultiMoveToBottom = function() {
|
||||
// Anything selected?
|
||||
if(self.multiEditItems().length < 1) return;
|
||||
|
||||
// Move each item to the bottom, starting from the first one in the sorted list
|
||||
var arrayList = self.multiEditItems()
|
||||
var movePromises = [];
|
||||
for(var i = 0; i < arrayList.length; i++) {
|
||||
movePromises.push(callAPI({
|
||||
mode: "switch",
|
||||
value: arrayList[i].id,
|
||||
value2: self.totalItems() - 1
|
||||
}));
|
||||
}
|
||||
|
||||
// Wait for all moves to complete then refresh
|
||||
Promise.all(movePromises).then(function() {
|
||||
self.parent.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
// Focus on the confirm button
|
||||
$('#modal-delete-queue-job').on("shown.bs.modal", function() {
|
||||
$('#modal-delete-queue-job .btn[type="submit"]').focus()
|
||||
})
|
||||
|
||||
// On change of page we need to check all those that were in the list!
|
||||
self.queueItems.subscribe(function() {
|
||||
// We need to wait until the unit is actually finished rendering
|
||||
@@ -460,7 +529,7 @@ function QueueListModel(parent) {
|
||||
})
|
||||
|
||||
// Update check-all buton state
|
||||
setCheckAllState('#multiedit-checkall', '.queue-table input[name="multiedit"]')
|
||||
setCheckAllState('#multiedit-checkall-queue', '.queue-table input[name="multiedit"]')
|
||||
}, 100)
|
||||
}, null, "arrayChange")
|
||||
}
|
||||
@@ -471,6 +540,7 @@ function QueueListModel(parent) {
|
||||
function QueueModel(parent, data) {
|
||||
var self = this;
|
||||
self.parent = parent;
|
||||
self.rawLabels = []
|
||||
|
||||
// Job info
|
||||
self.id = data.nzo_id;
|
||||
@@ -478,8 +548,9 @@ function QueueModel(parent, data) {
|
||||
self.password = ko.observable(data.password);
|
||||
self.index = ko.observable(data.index);
|
||||
self.status = ko.observable(data.status);
|
||||
self.isGrabbing = ko.observable(data.status == 'Grabbing' || data.avg_age == '-')
|
||||
self.isFetchingBlocks = data.status == 'Fetching' || data.priority == 'Repair' // No need to update
|
||||
self.labels = ko.observableArray(data.labels);
|
||||
self.isGrabbing = ko.observable(data.status === 'Grabbing' || data.avg_age === '-')
|
||||
self.isFetchingBlocks = data.status === 'Fetching' || data.priority === 'Repair' // No need to update
|
||||
self.totalMB = ko.observable(parseFloat(data.mb));
|
||||
self.remainingMB = ko.observable(parseFloat(data.mbleft))
|
||||
self.missingMB = ko.observable(parseFloat(data.mbmissing))
|
||||
@@ -490,7 +561,7 @@ function QueueModel(parent, data) {
|
||||
self.priority = ko.observable(parent.priorityName[data.priority]);
|
||||
self.script = ko.observable(data.script);
|
||||
self.unpackopts = ko.observable(parseInt(data.unpackopts)) // UnpackOpts fails if not parseInt'd!
|
||||
self.pausedStatus = ko.observable(data.status == 'Paused');
|
||||
self.pausedStatus = ko.observable(data.status === 'Paused');
|
||||
self.timeLeft = ko.observable(data.timeleft);
|
||||
|
||||
// Initially empty
|
||||
@@ -501,7 +572,7 @@ function QueueModel(parent, data) {
|
||||
// Color of the progress bar
|
||||
self.progressColor = ko.computed(function() {
|
||||
// Checking
|
||||
if(self.status() == 'Checking') {
|
||||
if(self.status() === 'Checking') {
|
||||
return '#58A9FA'
|
||||
}
|
||||
// Check for missing data, the value is arbitrary! (2%)
|
||||
@@ -509,7 +580,7 @@ function QueueModel(parent, data) {
|
||||
return '#F8A34E'
|
||||
}
|
||||
// Set to grey, only when not Force download
|
||||
if((self.parent.parent.downloadsPaused() && self.priority() != 2) || self.pausedStatus()) {
|
||||
if((self.parent.parent.downloadsPaused() && self.priority() !== 2) || self.pausedStatus()) {
|
||||
return '#B7B7B7'
|
||||
}
|
||||
// Nothing
|
||||
@@ -518,6 +589,9 @@ function QueueModel(parent, data) {
|
||||
|
||||
// MB's
|
||||
self.progressText = ko.pureComputed(function() {
|
||||
if(self.isGrabbing()) {
|
||||
return glitterTranslate.fetchingURL
|
||||
}
|
||||
return (self.totalMB() - self.remainingMB()).toFixed(0) + " MB / " + (self.totalMB() * 1).toFixed(0) + " MB";
|
||||
})
|
||||
|
||||
@@ -530,23 +604,22 @@ function QueueModel(parent, data) {
|
||||
return self.name()
|
||||
})
|
||||
self.missingText = ko.pureComputed(function() {
|
||||
// Check for missing data, the value is arbitrary! (1%)
|
||||
if(self.missingMB()/self.totalMB() > 0.01) {
|
||||
// Check for missing data, can show 0 if article-size is smaller than 500K, but we accept that
|
||||
if(self.missingMB()) {
|
||||
return self.missingMB().toFixed(0) + ' MB ' + glitterTranslate.misingArt
|
||||
}
|
||||
return;
|
||||
})
|
||||
self.statusText = ko.computed(function() {
|
||||
// Checking
|
||||
if(self.status() == 'Checking') {
|
||||
if(self.status() === 'Checking') {
|
||||
return glitterTranslate.checking
|
||||
}
|
||||
// Grabbing
|
||||
if(self.status() == 'Grabbing') {
|
||||
if(self.status() === 'Grabbing') {
|
||||
return glitterTranslate.fetch
|
||||
}
|
||||
// Pausing status
|
||||
if((self.parent.parent.downloadsPaused() && self.priority() != 2) || self.pausedStatus()) {
|
||||
if((self.parent.parent.downloadsPaused() && self.priority() !== 2) || self.pausedStatus()) {
|
||||
return glitterTranslate.paused;
|
||||
}
|
||||
// Just the time
|
||||
@@ -556,7 +629,7 @@ function QueueModel(parent, data) {
|
||||
// Icon to better show force-priority
|
||||
self.queueIcon = ko.computed(function() {
|
||||
// Force comes first
|
||||
if(self.priority() == 2) {
|
||||
if(self.priority() === 2) {
|
||||
return 'glyphicon-forward'
|
||||
}
|
||||
if(self.pausedStatus()) {
|
||||
@@ -565,30 +638,29 @@ function QueueModel(parent, data) {
|
||||
return 'glyphicon-pause'
|
||||
})
|
||||
|
||||
// Extra queue column
|
||||
self.extraText = ko.pureComputed(function() {
|
||||
// Picked anything?
|
||||
switch(self.parent.parent.extraQueueColumn()) {
|
||||
// Extra queue columns
|
||||
self.showColumn = function(param) {
|
||||
switch(param) {
|
||||
case 'category':
|
||||
// Exception for *
|
||||
if(self.category() == "*")
|
||||
if(self.category() === "*")
|
||||
return glitterTranslate.defaultText
|
||||
return self.category();
|
||||
case 'priority':
|
||||
// Onload-exception
|
||||
if(self.priority() == undefined) return;
|
||||
return ko.utils.arrayFirst(self.parent.priorityOptions(), function(item) { return item.value == self.priority()}).name;
|
||||
if(self.priority() === undefined) return;
|
||||
return ko.utils.arrayFirst(self.parent.priorityOptions(), function(item) { return item.value === self.priority()}).name;
|
||||
case 'processing':
|
||||
// Onload-exception
|
||||
if(self.unpackopts() == undefined) return;
|
||||
return ko.utils.arrayFirst(self.parent.processingOptions(), function(item) { return item.value == self.unpackopts()}).name;
|
||||
if(self.unpackopts() === undefined) return;
|
||||
return ko.utils.arrayFirst(self.parent.processingOptions(), function(item) { return item.value === self.unpackopts()}).name;
|
||||
case 'scripts':
|
||||
return self.script();
|
||||
case 'age':
|
||||
return self.avg_age();
|
||||
}
|
||||
return;
|
||||
})
|
||||
};
|
||||
|
||||
// Every update
|
||||
self.updateFromData = function(data) {
|
||||
@@ -597,7 +669,7 @@ function QueueModel(parent, data) {
|
||||
self.password(data.password);
|
||||
self.index(data.index);
|
||||
self.status(data.status)
|
||||
self.isGrabbing(data.status == 'Grabbing' || data.avg_age == '-')
|
||||
self.isGrabbing(data.status === 'Grabbing' || data.avg_age === '-')
|
||||
self.totalMB(parseFloat(data.mb));
|
||||
self.remainingMB(parseFloat(data.mbleft));
|
||||
self.missingMB(parseFloat(data.mbmissing))
|
||||
@@ -608,8 +680,16 @@ function QueueModel(parent, data) {
|
||||
self.priority(parent.priorityName[data.priority]);
|
||||
self.script(data.script);
|
||||
self.unpackopts(parseInt(data.unpackopts)) // UnpackOpts fails if not parseInt'd!
|
||||
self.pausedStatus(data.status == 'Paused');
|
||||
self.pausedStatus(data.status === 'Paused');
|
||||
self.timeLeft(data.timeleft);
|
||||
|
||||
// Did the label-list change?
|
||||
// Otherwise KO will send updates to all texts during refresh()
|
||||
if(self.rawLabels !== data.labels.toString()) {
|
||||
// Update
|
||||
self.labels(data.labels);
|
||||
self.rawLabels = data.labels.toString();
|
||||
}
|
||||
};
|
||||
|
||||
// Pause individual download
|
||||
@@ -630,9 +710,37 @@ function QueueModel(parent, data) {
|
||||
self.editingName(true)
|
||||
self.nameForEdit(self.name())
|
||||
|
||||
// Select
|
||||
$(event.target).parents('.name').find('input').select()
|
||||
}
|
||||
// Select the input
|
||||
const $input = $(event.target).parents('.name').find('input');
|
||||
$input.select();
|
||||
|
||||
// Add Tab/Shift+Tab navigation
|
||||
$input.off('keydown.tabnav').on('keydown.tabnav', function (e) {
|
||||
if (e.key === 'Tab') {
|
||||
e.preventDefault();
|
||||
|
||||
// Find all rename inputs that are currently visible
|
||||
const inputs = $('.queue-table input[type="text"]');
|
||||
const currentIndex = inputs.index(this);
|
||||
let nextIndex = e.shiftKey ? currentIndex - 1 : currentIndex + 1;
|
||||
|
||||
// Wrap around
|
||||
if (nextIndex >= inputs.length) nextIndex = 0;
|
||||
if (nextIndex < 0) nextIndex = inputs.length - 1;
|
||||
|
||||
// Simulate clicking Rename on the next row
|
||||
const $nextRow = inputs.eq(nextIndex).closest('tr');
|
||||
$nextRow.find('.hover-button[title="Rename"]').click();
|
||||
|
||||
// Delay focusing to wait for new input to appear
|
||||
setTimeout(() => {
|
||||
const $nextInput = $('.queue-table input[type="text"]').eq(nextIndex);
|
||||
$nextInput.focus().select();
|
||||
}, 50);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Catch the submit action
|
||||
self.editingNameSubmit = function() {
|
||||
@@ -642,7 +750,10 @@ function QueueModel(parent, data) {
|
||||
// Do on change
|
||||
self.nameForEdit.subscribe(function(newName) {
|
||||
// Anything change or empty?
|
||||
if(!newName || self.name() == newName) return;
|
||||
if(!newName || self.name() === newName) return;
|
||||
|
||||
// Rename would abort Direct Unpack, so ask if user is sure
|
||||
if(self.direct_unpack() && !confirm(glitterTranslate.renameAbort)) return;
|
||||
|
||||
// Send rename
|
||||
callAPI({
|
||||
@@ -683,8 +794,6 @@ function QueueModel(parent, data) {
|
||||
})
|
||||
}
|
||||
self.changeScript = function(item) {
|
||||
// Not on empty handlers
|
||||
if(!item.script() || parent.scriptsList().length <= 1) return;
|
||||
callAPI({
|
||||
mode: 'change_script',
|
||||
value: item.id,
|
||||
@@ -713,32 +822,5 @@ function QueueModel(parent, data) {
|
||||
})
|
||||
}
|
||||
|
||||
// Remove 1 download from queue
|
||||
self.removeDownload = function(item, event) {
|
||||
// Confirm and remove
|
||||
if(!self.parent.parent.confirmDeleteQueue() || confirm(glitterTranslate.removeDow1)) {
|
||||
var itemToDelete = this;
|
||||
|
||||
// Show notification
|
||||
showNotification('.main-notification-box-removing')
|
||||
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'delete',
|
||||
del_files: 1,
|
||||
value: item.id
|
||||
}).then(function(response) {
|
||||
// Fade and remove
|
||||
$(event.currentTarget).parent().parent().fadeOut(fadeOnDeleteDuration, function() {
|
||||
// Make sure no flickering (if there are more items left) and then remove
|
||||
self.parent.isLoading(self.parent.totalItems() > 1)
|
||||
parent.queueItems.remove(itemToDelete);
|
||||
parent.multiEditItems.remove(function(inList) { return inList.id == itemToDelete.id; })
|
||||
self.parent.parent.refresh();
|
||||
// Hide notifcation
|
||||
hideNotification(true)
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
2
interfaces/Glitter/templates/static/javascripts/jquery-3.5.1.min.js
vendored
Normal file
2
interfaces/Glitter/templates/static/javascripts/jquery-3.5.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
12
interfaces/Glitter/templates/static/javascripts/jquery.hotkeys.min.js
vendored
Normal file
12
interfaces/Glitter/templates/static/javascripts/jquery.hotkeys.min.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* jQuery Hotkeys Plugin
|
||||
* Copyright 2010, John Resig
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
*
|
||||
* Based upon the plugin by Tzury Bar Yochay:
|
||||
* https://github.com/tzuryby/jquery.hotkeys
|
||||
*
|
||||
* Original idea by:
|
||||
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
|
||||
*/
|
||||
!function(c){function e(e){var o,f;"string"==typeof e.data&&(e.data={keys:e.data}),e.data&&e.data.keys&&"string"==typeof e.data.keys&&(o=e.handler,f=e.data.keys.toLowerCase().split(" "),e.handler=function(a){if(this===a.target||!(/textarea|select/i.test(a.target.nodeName)||c.hotkeys.options.filterTextInputs&&-1<c.inArray(a.target.type,c.hotkeys.textAcceptingInputTypes))){var s="keypress"!==a.type&&c.hotkeys.specialKeys[a.which],e=String.fromCharCode(a.which).toLowerCase(),r="",t={};c.each(["alt","ctrl","shift"],function(e,t){a[t+"Key"]&&s!==t&&(r+=t+"+")}),a.metaKey&&!a.ctrlKey&&"meta"!==s&&(r+="meta+"),a.metaKey&&"meta"!==s&&-1<r.indexOf("alt+ctrl+shift+")&&(r=r.replace("alt+ctrl+shift+","hyper+")),s?t[r+s]=!0:(t[r+e]=!0,t[r+c.hotkeys.shiftNums[e]]=!0,"shift+"===r&&(t[c.hotkeys.shiftNums[e]]=!0));for(var i=0,n=f.length;i<n;i++)if(t[f[i]])return o.apply(this,arguments)}})}c.hotkeys={version:"0.8",specialKeys:{8:"backspace",9:"tab",10:"return",13:"return",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",59:";",61:"=",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",106:"*",107:"+",109:"-",110:".",111:"/",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",144:"numlock",145:"scroll",173:"-",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},shiftNums:{"`":"~",1:"!",2:"@",3:"#",4:"$",5:"%",6:"^",7:"&",8:"*",9:"(",0:")","-":"_","=":"+",";":": ","'":'"',",":"<",".":">","/":"?","\\":"|"},textAcceptingInputTypes:["text","password","number","email","url","range","date","month","week","time","datetime","datetime-local","search","color","tel"],options:{filterTextInputs:!0}},c.each(["keydown","keyup","keypress"],function(){c.event.special[this]={add:e}})}(jQuery||this.jQuery||window.jQuery);
|
||||
File diff suppressed because one or more lines are too long
@@ -1,13 +1,7 @@
|
||||
// Peity jQuery plugin version 3.2.1
|
||||
// (c) 2016 Ben Pickles
|
||||
// Peity jQuery plugin version 3.3.0
|
||||
// (c) 2018 Ben Pickles
|
||||
//
|
||||
// http://benpickles.github.io/peity
|
||||
//
|
||||
// Released under MIT license.
|
||||
(function(k,w,h,v){var d=k.fn.peity=function(a,b){y&&this.each(function(){var e=k(this),c=e.data("_peity");c?(a&&(c.type=a),k.extend(c.opts,b)):(c=new x(e,a,k.extend({},d.defaults[a],e.data("peity"),b)),e.change(function(){c.draw()}).data("_peity",c));c.draw()});return this},x=function(a,b,e){this.$el=a;this.type=b;this.opts=e},o=x.prototype,q=o.svgElement=function(a,b){return k(w.createElementNS("http://www.w3.org/2000/svg",a)).attr(b)},y="createElementNS"in w&&q("svg",{})[0].createSVGRect;o.draw=
|
||||
function(){var a=this.opts;d.graphers[this.type].call(this,a);a.after&&a.after.call(this,a)};o.fill=function(){var a=this.opts.fill;return k.isFunction(a)?a:function(b,e){return a[e%a.length]}};o.prepare=function(a,b){this.$svg||this.$el.hide().after(this.$svg=q("svg",{"class":"peity"}));return this.$svg.empty().data("peity",this).attr({height:b,width:a})};o.values=function(){return k.map(this.$el.text().split(this.opts.delimiter),function(a){return parseFloat(a)})};d.defaults={};d.graphers={};d.register=
|
||||
function(a,b,e){this.defaults[a]=b;this.graphers[a]=e};d.register("pie",{fill:["#ff9900","#fff4dd","#ffc66e"],radius:8},function(a){if(!a.delimiter){var b=this.$el.text().match(/[^0-9\.]/);a.delimiter=b?b[0]:","}b=k.map(this.values(),function(a){return 0<a?a:0});if("/"==a.delimiter)var e=b[0],b=[e,h.max(0,b[1]-e)];for(var c=0,e=b.length,t=0;c<e;c++)t+=b[c];t||(e=2,t=1,b=[0,1]);var l=2*a.radius,l=this.prepare(a.width||l,a.height||l),c=l.width(),f=l.height(),j=c/2,d=f/2,f=h.min(j,d),a=a.innerRadius;
|
||||
"donut"==this.type&&!a&&(a=0.5*f);for(var r=h.PI,s=this.fill(),g=this.scale=function(a,b){var c=a/t*r*2-r/2;return[b*h.cos(c)+j,b*h.sin(c)+d]},m=0,c=0;c<e;c++){var u=b[c],i=u/t;if(0!=i){if(1==i)if(a)var i=j-0.01,p=d-f,n=d-a,i=q("path",{d:["M",j,p,"A",f,f,0,1,1,i,p,"L",i,n,"A",a,a,0,1,0,j,n].join(" ")});else i=q("circle",{cx:j,cy:d,r:f});else p=m+u,n=["M"].concat(g(m,f),"A",f,f,0,0.5<i?1:0,1,g(p,f),"L"),a?n=n.concat(g(p,a),"A",a,a,0,0.5<i?1:0,0,g(m,a)):n.push(j,d),m+=u,i=q("path",{d:n.join(" ")});
|
||||
i.attr("fill",s.call(this,u,c,b));l.append(i)}}});d.register("donut",k.extend(!0,{},d.defaults.pie),function(a){d.graphers.pie.call(this,a)});d.register("line",{delimiter:",",fill:"#c6d9fd",height:16,min:0,stroke:"#4d89f9",strokeWidth:1,width:32},function(a){var b=this.values();1==b.length&&b.push(b[0]);for(var e=h.max.apply(h,a.max==v?b:b.concat(a.max)),c=h.min.apply(h,a.min==v?b:b.concat(a.min)),d=this.prepare(a.width,a.height),l=a.strokeWidth,f=d.width(),j=d.height()-l,k=e-c,e=this.x=function(a){return a*
|
||||
(f/(b.length-1))},r=this.y=function(a){var b=j;k&&(b-=(a-c)/k*j);return b+l/2},s=r(h.max(c,0)),g=[0,s],m=0;m<b.length;m++)g.push(e(m),r(b[m]));g.push(f,s);a.fill&&d.append(q("polygon",{fill:a.fill,points:g.join(" ")}));l&&d.append(q("polyline",{fill:"none",points:g.slice(2,g.length-2).join(" "),stroke:a.stroke,"stroke-width":l,"stroke-linecap":"square"}))});d.register("bar",{delimiter:",",fill:["#4D89F9"],height:16,min:0,padding:0.1,width:32},function(a){for(var b=this.values(),e=h.max.apply(h,a.max==
|
||||
v?b:b.concat(a.max)),c=h.min.apply(h,a.min==v?b:b.concat(a.min)),d=this.prepare(a.width,a.height),l=d.width(),f=d.height(),j=e-c,a=a.padding,k=this.fill(),r=this.x=function(a){return a*l/b.length},s=this.y=function(a){return f-(j?(a-c)/j*f:1)},g=0;g<b.length;g++){var m=r(g+a),u=r(g+1-a)-m,i=b[g],p=s(i),n=p,o;j?0>i?n=s(h.min(e,0)):p=s(h.max(c,0)):o=1;o=p-n;0==o&&(o=1,0<e&&j&&n--);d.append(q("rect",{fill:k.call(this,i,g,b),x:m,y:n,width:u,height:o}))}})})(jQuery,document,Math);
|
||||
!function(t,i,e,n){var a=t.fn.peity=function(i,e){return l&&this.each(function(){var n=t(this),h=n.data("_peity");h?(i&&(h.type=i),t.extend(h.opts,e)):(h=new r(n,i,t.extend({},a.defaults[i],n.data("peity"),e)),n.change(function(){h.draw()}).data("_peity",h)),h.draw()}),this},r=function(t,i,e){this.$el=t,this.type=i,this.opts=e},h=r.prototype,s=h.svgElement=function(e,n){return t(i.createElementNS("http://www.w3.org/2000/svg",e)).attr(n)},l="createElementNS"in i&&s("svg",{})[0].createSVGRect;h.draw=function(){var t=this.opts;a.graphers[this.type].call(this,t),t.after&&t.after.call(this,t)},h.fill=function(){var i=this.opts.fill;return t.isFunction(i)?i:function(t,e){return i[e%i.length]}},h.prepare=function(t,i){return this.$svg||this.$el.hide().after(this.$svg=s("svg",{class:"peity"})),this.$svg.empty().data("_peity",this).attr({height:i,width:t})},h.values=function(){return t.map(this.$el.text().split(this.opts.delimiter),function(t){return parseFloat(t)})},a.defaults={},a.graphers={},a.register=function(t,i,e){this.defaults[t]=i,this.graphers[t]=e},a.register("pie",{fill:["#ff9900","#fff4dd","#ffc66e"],radius:8},function(i){if(!i.delimiter){var n=this.$el.text().match(/[^0-9\.]/);i.delimiter=n?n[0]:","}var a=t.map(this.values(),function(t){return t>0?t:0});if("/"==i.delimiter){var r=a[0],h=a[1];a=[r,e.max(0,h-r)]}for(var l=0,p=a.length,o=0;l<p;l++)o+=a[l];o||(p=2,o=1,a=[0,1]);var f=2*i.radius,c=this.prepare(i.width||f,i.height||f),u=c.width()/2,d=c.height()/2,g=e.min(u,d),v=i.innerRadius;"donut"!=this.type||v||(v=.5*g);var m=e.PI,y=this.fill(),w=this.scale=function(t,i){var n=t/o*m*2-m/2;return[i*e.cos(n)+u,i*e.sin(n)+d]},x=0;for(l=0;l<p;l++){var k,$=a[l],j=$/o;if(0!=j){if(1==j)if(v){var A=u-.01,E=d-g,F=d-v;k=s("path",{d:["M",u,E,"A",g,g,0,1,1,A,E,"L",A,F,"A",v,v,0,1,0,u,F].join(" "),"data-value":$})}else k=s("circle",{cx:u,cy:d,"data-value":$,r:g});else{var M=x+$,S=["M"].concat(w(x,g),"A",g,g,0,j>.5?1:0,1,w(M,g),"L");v?S=S.concat(w(M,v),"A",v,v,0,j>.5?1:0,0,w(x,v)):S.push(u,d),x+=$,k=s("path",{d:S.join(" "),"data-value":$})}k.attr("fill",y.call(this,$,l,a)),c.append(k)}}}),a.register("donut",t.extend(!0,{},a.defaults.pie),function(t){a.graphers.pie.call(this,t)}),a.register("line",{delimiter:",",fill:"#c6d9fd",height:16,min:0,stroke:"#4d89f9",strokeWidth:1,width:32},function(t){var i=this.values();1==i.length&&i.push(i[0]);for(var a=e.max.apply(e,t.max==n?i:i.concat(t.max)),r=e.min.apply(e,t.min==n?i:i.concat(t.min)),h=this.prepare(t.width,t.height),l=t.strokeWidth,p=h.width(),o=h.height()-l,f=a-r,c=this.x=function(t){return t*(p/(i.length-1))},u=this.y=function(t){var i=o;return f&&(i-=(t-r)/f*o),i+l/2},d=u(e.max(r,0)),g=[0,d],v=0;v<i.length;v++)g.push(c(v),u(i[v]));g.push(p,d),t.fill&&h.append(s("polygon",{fill:t.fill,points:g.join(" ")})),l&&h.append(s("polyline",{fill:"none",points:g.slice(2,g.length-2).join(" "),stroke:t.stroke,"stroke-width":l,"stroke-linecap":"square"}))}),a.register("bar",{delimiter:",",fill:["#4D89F9"],height:16,min:0,padding:.1,width:32},function(t){for(var i=this.values(),a=e.max.apply(e,t.max==n?i:i.concat(t.max)),r=e.min.apply(e,t.min==n?i:i.concat(t.min)),h=this.prepare(t.width,t.height),l=h.width(),p=h.height(),o=a-r,f=t.padding,c=this.fill(),u=this.x=function(t){return t*l/i.length},d=this.y=function(t){return p-(o?(t-r)/o*p:1)},g=0;g<i.length;g++){var v,m=u(g+f),y=u(g+1-f)-m,w=i[g],x=d(w),k=x,$=x;o?w<0?k=d(e.min(a,0)):$=d(e.max(r,0)):v=1,0==(v=$-k)&&(v=1,a>0&&o&&k--),h.append(s("rect",{"data-value":w,fill:c.call(this,w,g,i),x:m,y:k,width:y,height:v}))}})}(jQuery,document,Math);
|
||||
139
interfaces/Glitter/templates/static/javascripts/knockout-3.5.1.min.js
vendored
Normal file
139
interfaces/Glitter/templates/static/javascripts/knockout-3.5.1.min.js
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
/*!
|
||||
* Knockout JavaScript library v3.5.1
|
||||
* (c) The Knockout.js team - http://knockoutjs.com/
|
||||
* License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
(function() {(function(n){var A=this||(0,eval)("this"),w=A.document,R=A.navigator,v=A.jQuery,H=A.JSON;v||"undefined"===typeof jQuery||(v=jQuery);(function(n){"function"===typeof define&&define.amd?define(["exports","require"],n):"object"===typeof exports&&"object"===typeof module?n(module.exports||exports):n(A.ko={})})(function(S,T){function K(a,c){return null===a||typeof a in W?a===c:!1}function X(b,c){var d;return function(){d||(d=a.a.setTimeout(function(){d=n;b()},c))}}function Y(b,c){var d;return function(){clearTimeout(d);
|
||||
d=a.a.setTimeout(b,c)}}function Z(a,c){c&&"change"!==c?"beforeChange"===c?this.pc(a):this.gb(a,c):this.qc(a)}function aa(a,c){null!==c&&c.s&&c.s()}function ba(a,c){var d=this.qd,e=d[r];e.ra||(this.Qb&&this.mb[c]?(d.uc(c,a,this.mb[c]),this.mb[c]=null,--this.Qb):e.I[c]||d.uc(c,a,e.J?{da:a}:d.$c(a)),a.Ja&&a.gd())}var a="undefined"!==typeof S?S:{};a.b=function(b,c){for(var d=b.split("."),e=a,f=0;f<d.length-1;f++)e=e[d[f]];e[d[d.length-1]]=c};a.L=function(a,c,d){a[c]=d};a.version="3.5.1";a.b("version",
|
||||
a.version);a.options={deferUpdates:!1,useOnlyNativeEvents:!1,foreachHidesDestroyed:!1};a.a=function(){function b(a,b){for(var c in a)f.call(a,c)&&b(c,a[c])}function c(a,b){if(b)for(var c in b)f.call(b,c)&&(a[c]=b[c]);return a}function d(a,b){a.__proto__=b;return a}function e(b,c,d,e){var l=b[c].match(q)||[];a.a.D(d.match(q),function(b){a.a.Na(l,b,e)});b[c]=l.join(" ")}var f=Object.prototype.hasOwnProperty,g={__proto__:[]}instanceof Array,h="function"===typeof Symbol,m={},k={};m[R&&/Firefox\/2/i.test(R.userAgent)?
|
||||
"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];m.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");b(m,function(a,b){if(b.length)for(var c=0,d=b.length;c<d;c++)k[b[c]]=a});var l={propertychange:!0},p=w&&function(){for(var a=3,b=w.createElement("div"),c=b.getElementsByTagName("i");b.innerHTML="\x3c!--[if gt IE "+ ++a+"]><i></i><![endif]--\x3e",c[0];);return 4<a?a:n}(),q=/\S+/g,t;return{Jc:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],
|
||||
D:function(a,b,c){for(var d=0,e=a.length;d<e;d++)b.call(c,a[d],d,a)},A:"function"==typeof Array.prototype.indexOf?function(a,b){return Array.prototype.indexOf.call(a,b)}:function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},Lb:function(a,b,c){for(var d=0,e=a.length;d<e;d++)if(b.call(c,a[d],d,a))return a[d];return n},Pa:function(b,c){var d=a.a.A(b,c);0<d?b.splice(d,1):0===d&&b.shift()},wc:function(b){var c=[];b&&a.a.D(b,function(b){0>a.a.A(c,b)&&c.push(b)});return c},Mb:function(a,
|
||||
b,c){var d=[];if(a)for(var e=0,l=a.length;e<l;e++)d.push(b.call(c,a[e],e));return d},jb:function(a,b,c){var d=[];if(a)for(var e=0,l=a.length;e<l;e++)b.call(c,a[e],e)&&d.push(a[e]);return d},Nb:function(a,b){if(b instanceof Array)a.push.apply(a,b);else for(var c=0,d=b.length;c<d;c++)a.push(b[c]);return a},Na:function(b,c,d){var e=a.a.A(a.a.bc(b),c);0>e?d&&b.push(c):d||b.splice(e,1)},Ba:g,extend:c,setPrototypeOf:d,Ab:g?d:c,P:b,Ga:function(a,b,c){if(!a)return a;var d={},e;for(e in a)f.call(a,e)&&(d[e]=
|
||||
b.call(c,a[e],e,a));return d},Tb:function(b){for(;b.firstChild;)a.removeNode(b.firstChild)},Yb:function(b){b=a.a.la(b);for(var c=(b[0]&&b[0].ownerDocument||w).createElement("div"),d=0,e=b.length;d<e;d++)c.appendChild(a.oa(b[d]));return c},Ca:function(b,c){for(var d=0,e=b.length,l=[];d<e;d++){var k=b[d].cloneNode(!0);l.push(c?a.oa(k):k)}return l},va:function(b,c){a.a.Tb(b);if(c)for(var d=0,e=c.length;d<e;d++)b.appendChild(c[d])},Xc:function(b,c){var d=b.nodeType?[b]:b;if(0<d.length){for(var e=d[0],
|
||||
l=e.parentNode,k=0,f=c.length;k<f;k++)l.insertBefore(c[k],e);k=0;for(f=d.length;k<f;k++)a.removeNode(d[k])}},Ua:function(a,b){if(a.length){for(b=8===b.nodeType&&b.parentNode||b;a.length&&a[0].parentNode!==b;)a.splice(0,1);for(;1<a.length&&a[a.length-1].parentNode!==b;)a.length--;if(1<a.length){var c=a[0],d=a[a.length-1];for(a.length=0;c!==d;)a.push(c),c=c.nextSibling;a.push(d)}}return a},Zc:function(a,b){7>p?a.setAttribute("selected",b):a.selected=b},Db:function(a){return null===a||a===n?"":a.trim?
|
||||
a.trim():a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},Ud:function(a,b){a=a||"";return b.length>a.length?!1:a.substring(0,b.length)===b},vd:function(a,b){if(a===b)return!0;if(11===a.nodeType)return!1;if(b.contains)return b.contains(1!==a.nodeType?a.parentNode:a);if(b.compareDocumentPosition)return 16==(b.compareDocumentPosition(a)&16);for(;a&&a!=b;)a=a.parentNode;return!!a},Sb:function(b){return a.a.vd(b,b.ownerDocument.documentElement)},kd:function(b){return!!a.a.Lb(b,a.a.Sb)},R:function(a){return a&&
|
||||
a.tagName&&a.tagName.toLowerCase()},Ac:function(b){return a.onError?function(){try{return b.apply(this,arguments)}catch(c){throw a.onError&&a.onError(c),c;}}:b},setTimeout:function(b,c){return setTimeout(a.a.Ac(b),c)},Gc:function(b){setTimeout(function(){a.onError&&a.onError(b);throw b;},0)},B:function(b,c,d){var e=a.a.Ac(d);d=l[c];if(a.options.useOnlyNativeEvents||d||!v)if(d||"function"!=typeof b.addEventListener)if("undefined"!=typeof b.attachEvent){var k=function(a){e.call(b,a)},f="on"+c;b.attachEvent(f,
|
||||
k);a.a.K.za(b,function(){b.detachEvent(f,k)})}else throw Error("Browser doesn't support addEventListener or attachEvent");else b.addEventListener(c,e,!1);else t||(t="function"==typeof v(b).on?"on":"bind"),v(b)[t](c,e)},Fb:function(b,c){if(!b||!b.nodeType)throw Error("element must be a DOM node when calling triggerEvent");var d;"input"===a.a.R(b)&&b.type&&"click"==c.toLowerCase()?(d=b.type,d="checkbox"==d||"radio"==d):d=!1;if(a.options.useOnlyNativeEvents||!v||d)if("function"==typeof w.createEvent)if("function"==
|
||||
typeof b.dispatchEvent)d=w.createEvent(k[c]||"HTMLEvents"),d.initEvent(c,!0,!0,A,0,0,0,0,0,!1,!1,!1,!1,0,b),b.dispatchEvent(d);else throw Error("The supplied element doesn't support dispatchEvent");else if(d&&b.click)b.click();else if("undefined"!=typeof b.fireEvent)b.fireEvent("on"+c);else throw Error("Browser doesn't support triggering events");else v(b).trigger(c)},f:function(b){return a.O(b)?b():b},bc:function(b){return a.O(b)?b.v():b},Eb:function(b,c,d){var l;c&&("object"===typeof b.classList?
|
||||
(l=b.classList[d?"add":"remove"],a.a.D(c.match(q),function(a){l.call(b.classList,a)})):"string"===typeof b.className.baseVal?e(b.className,"baseVal",c,d):e(b,"className",c,d))},Bb:function(b,c){var d=a.a.f(c);if(null===d||d===n)d="";var e=a.h.firstChild(b);!e||3!=e.nodeType||a.h.nextSibling(e)?a.h.va(b,[b.ownerDocument.createTextNode(d)]):e.data=d;a.a.Ad(b)},Yc:function(a,b){a.name=b;if(7>=p)try{var c=a.name.replace(/[&<>'"]/g,function(a){return"&#"+a.charCodeAt(0)+";"});a.mergeAttributes(w.createElement("<input name='"+
|
||||
c+"'/>"),!1)}catch(d){}},Ad:function(a){9<=p&&(a=1==a.nodeType?a:a.parentNode,a.style&&(a.style.zoom=a.style.zoom))},wd:function(a){if(p){var b=a.style.width;a.style.width=0;a.style.width=b}},Pd:function(b,c){b=a.a.f(b);c=a.a.f(c);for(var d=[],e=b;e<=c;e++)d.push(e);return d},la:function(a){for(var b=[],c=0,d=a.length;c<d;c++)b.push(a[c]);return b},Da:function(a){return h?Symbol(a):a},Zd:6===p,$d:7===p,W:p,Lc:function(b,c){for(var d=a.a.la(b.getElementsByTagName("input")).concat(a.a.la(b.getElementsByTagName("textarea"))),
|
||||
e="string"==typeof c?function(a){return a.name===c}:function(a){return c.test(a.name)},l=[],k=d.length-1;0<=k;k--)e(d[k])&&l.push(d[k]);return l},Nd:function(b){return"string"==typeof b&&(b=a.a.Db(b))?H&&H.parse?H.parse(b):(new Function("return "+b))():null},hc:function(b,c,d){if(!H||!H.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
|
||||
return H.stringify(a.a.f(b),c,d)},Od:function(c,d,e){e=e||{};var l=e.params||{},k=e.includeFields||this.Jc,f=c;if("object"==typeof c&&"form"===a.a.R(c))for(var f=c.action,h=k.length-1;0<=h;h--)for(var g=a.a.Lc(c,k[h]),m=g.length-1;0<=m;m--)l[g[m].name]=g[m].value;d=a.a.f(d);var p=w.createElement("form");p.style.display="none";p.action=f;p.method="post";for(var q in d)c=w.createElement("input"),c.type="hidden",c.name=q,c.value=a.a.hc(a.a.f(d[q])),p.appendChild(c);b(l,function(a,b){var c=w.createElement("input");
|
||||
c.type="hidden";c.name=a;c.value=b;p.appendChild(c)});w.body.appendChild(p);e.submitter?e.submitter(p):p.submit();setTimeout(function(){p.parentNode.removeChild(p)},0)}}}();a.b("utils",a.a);a.b("utils.arrayForEach",a.a.D);a.b("utils.arrayFirst",a.a.Lb);a.b("utils.arrayFilter",a.a.jb);a.b("utils.arrayGetDistinctValues",a.a.wc);a.b("utils.arrayIndexOf",a.a.A);a.b("utils.arrayMap",a.a.Mb);a.b("utils.arrayPushAll",a.a.Nb);a.b("utils.arrayRemoveItem",a.a.Pa);a.b("utils.cloneNodes",a.a.Ca);a.b("utils.createSymbolOrString",
|
||||
a.a.Da);a.b("utils.extend",a.a.extend);a.b("utils.fieldsIncludedWithJsonPost",a.a.Jc);a.b("utils.getFormFields",a.a.Lc);a.b("utils.objectMap",a.a.Ga);a.b("utils.peekObservable",a.a.bc);a.b("utils.postJson",a.a.Od);a.b("utils.parseJson",a.a.Nd);a.b("utils.registerEventHandler",a.a.B);a.b("utils.stringifyJson",a.a.hc);a.b("utils.range",a.a.Pd);a.b("utils.toggleDomNodeCssClass",a.a.Eb);a.b("utils.triggerEvent",a.a.Fb);a.b("utils.unwrapObservable",a.a.f);a.b("utils.objectForEach",a.a.P);a.b("utils.addOrRemoveItem",
|
||||
a.a.Na);a.b("utils.setTextContent",a.a.Bb);a.b("unwrap",a.a.f);Function.prototype.bind||(Function.prototype.bind=function(a){var c=this;if(1===arguments.length)return function(){return c.apply(a,arguments)};var d=Array.prototype.slice.call(arguments,1);return function(){var e=d.slice(0);e.push.apply(e,arguments);return c.apply(a,e)}});a.a.g=new function(){var b=0,c="__ko__"+(new Date).getTime(),d={},e,f;a.a.W?(e=function(a,e){var f=a[c];if(!f||"null"===f||!d[f]){if(!e)return n;f=a[c]="ko"+b++;d[f]=
|
||||
{}}return d[f]},f=function(a){var b=a[c];return b?(delete d[b],a[c]=null,!0):!1}):(e=function(a,b){var d=a[c];!d&&b&&(d=a[c]={});return d},f=function(a){return a[c]?(delete a[c],!0):!1});return{get:function(a,b){var c=e(a,!1);return c&&c[b]},set:function(a,b,c){(a=e(a,c!==n))&&(a[b]=c)},Ub:function(a,b,c){a=e(a,!0);return a[b]||(a[b]=c)},clear:f,Z:function(){return b++ +c}}};a.b("utils.domData",a.a.g);a.b("utils.domData.clear",a.a.g.clear);a.a.K=new function(){function b(b,c){var d=a.a.g.get(b,e);
|
||||
d===n&&c&&(d=[],a.a.g.set(b,e,d));return d}function c(c){var e=b(c,!1);if(e)for(var e=e.slice(0),k=0;k<e.length;k++)e[k](c);a.a.g.clear(c);a.a.K.cleanExternalData(c);g[c.nodeType]&&d(c.childNodes,!0)}function d(b,d){for(var e=[],l,f=0;f<b.length;f++)if(!d||8===b[f].nodeType)if(c(e[e.length]=l=b[f]),b[f]!==l)for(;f--&&-1==a.a.A(e,b[f]););}var e=a.a.g.Z(),f={1:!0,8:!0,9:!0},g={1:!0,9:!0};return{za:function(a,c){if("function"!=typeof c)throw Error("Callback must be a function");b(a,!0).push(c)},yb:function(c,
|
||||
d){var f=b(c,!1);f&&(a.a.Pa(f,d),0==f.length&&a.a.g.set(c,e,n))},oa:function(b){a.u.G(function(){f[b.nodeType]&&(c(b),g[b.nodeType]&&d(b.getElementsByTagName("*")))});return b},removeNode:function(b){a.oa(b);b.parentNode&&b.parentNode.removeChild(b)},cleanExternalData:function(a){v&&"function"==typeof v.cleanData&&v.cleanData([a])}}};a.oa=a.a.K.oa;a.removeNode=a.a.K.removeNode;a.b("cleanNode",a.oa);a.b("removeNode",a.removeNode);a.b("utils.domNodeDisposal",a.a.K);a.b("utils.domNodeDisposal.addDisposeCallback",
|
||||
a.a.K.za);a.b("utils.domNodeDisposal.removeDisposeCallback",a.a.K.yb);(function(){var b=[0,"",""],c=[1,"<table>","</table>"],d=[3,"<table><tbody><tr>","</tr></tbody></table>"],e=[1,"<select multiple='multiple'>","</select>"],f={thead:c,tbody:c,tfoot:c,tr:[2,"<table><tbody>","</tbody></table>"],td:d,th:d,option:e,optgroup:e},g=8>=a.a.W;a.a.ua=function(c,d){var e;if(v)if(v.parseHTML)e=v.parseHTML(c,d)||[];else{if((e=v.clean([c],d))&&e[0]){for(var l=e[0];l.parentNode&&11!==l.parentNode.nodeType;)l=l.parentNode;
|
||||
l.parentNode&&l.parentNode.removeChild(l)}}else{(e=d)||(e=w);var l=e.parentWindow||e.defaultView||A,p=a.a.Db(c).toLowerCase(),q=e.createElement("div"),t;t=(p=p.match(/^(?:\x3c!--.*?--\x3e\s*?)*?<([a-z]+)[\s>]/))&&f[p[1]]||b;p=t[0];t="ignored<div>"+t[1]+c+t[2]+"</div>";"function"==typeof l.innerShiv?q.appendChild(l.innerShiv(t)):(g&&e.body.appendChild(q),q.innerHTML=t,g&&q.parentNode.removeChild(q));for(;p--;)q=q.lastChild;e=a.a.la(q.lastChild.childNodes)}return e};a.a.Md=function(b,c){var d=a.a.ua(b,
|
||||
c);return d.length&&d[0].parentElement||a.a.Yb(d)};a.a.fc=function(b,c){a.a.Tb(b);c=a.a.f(c);if(null!==c&&c!==n)if("string"!=typeof c&&(c=c.toString()),v)v(b).html(c);else for(var d=a.a.ua(c,b.ownerDocument),e=0;e<d.length;e++)b.appendChild(d[e])}})();a.b("utils.parseHtmlFragment",a.a.ua);a.b("utils.setHtml",a.a.fc);a.aa=function(){function b(c,e){if(c)if(8==c.nodeType){var f=a.aa.Uc(c.nodeValue);null!=f&&e.push({ud:c,Kd:f})}else if(1==c.nodeType)for(var f=0,g=c.childNodes,h=g.length;f<h;f++)b(g[f],
|
||||
e)}var c={};return{Xb:function(a){if("function"!=typeof a)throw Error("You can only pass a function to ko.memoization.memoize()");var b=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);c[b]=a;return"\x3c!--[ko_memo:"+b+"]--\x3e"},bd:function(a,b){var f=c[a];if(f===n)throw Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized.");try{return f.apply(null,b||[]),!0}finally{delete c[a]}},cd:function(c,e){var f=
|
||||
[];b(c,f);for(var g=0,h=f.length;g<h;g++){var m=f[g].ud,k=[m];e&&a.a.Nb(k,e);a.aa.bd(f[g].Kd,k);m.nodeValue="";m.parentNode&&m.parentNode.removeChild(m)}},Uc:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:null}}}();a.b("memoization",a.aa);a.b("memoization.memoize",a.aa.Xb);a.b("memoization.unmemoize",a.aa.bd);a.b("memoization.parseMemoText",a.aa.Uc);a.b("memoization.unmemoizeDomNodeAndDescendants",a.aa.cd);a.na=function(){function b(){if(f)for(var b=f,c=0,d;h<f;)if(d=e[h++]){if(h>b){if(5E3<=
|
||||
++c){h=f;a.a.Gc(Error("'Too much recursion' after processing "+c+" task groups."));break}b=f}try{d()}catch(p){a.a.Gc(p)}}}function c(){b();h=f=e.length=0}var d,e=[],f=0,g=1,h=0;A.MutationObserver?d=function(a){var b=w.createElement("div");(new MutationObserver(a)).observe(b,{attributes:!0});return function(){b.classList.toggle("foo")}}(c):d=w&&"onreadystatechange"in w.createElement("script")?function(a){var b=w.createElement("script");b.onreadystatechange=function(){b.onreadystatechange=null;w.documentElement.removeChild(b);
|
||||
b=null;a()};w.documentElement.appendChild(b)}:function(a){setTimeout(a,0)};return{scheduler:d,zb:function(b){f||a.na.scheduler(c);e[f++]=b;return g++},cancel:function(a){a=a-(g-f);a>=h&&a<f&&(e[a]=null)},resetForTesting:function(){var a=f-h;h=f=e.length=0;return a},Sd:b}}();a.b("tasks",a.na);a.b("tasks.schedule",a.na.zb);a.b("tasks.runEarly",a.na.Sd);a.Ta={throttle:function(b,c){b.throttleEvaluation=c;var d=null;return a.$({read:b,write:function(e){clearTimeout(d);d=a.a.setTimeout(function(){b(e)},
|
||||
c)}})},rateLimit:function(a,c){var d,e,f;"number"==typeof c?d=c:(d=c.timeout,e=c.method);a.Hb=!1;f="function"==typeof e?e:"notifyWhenChangesStop"==e?Y:X;a.ub(function(a){return f(a,d,c)})},deferred:function(b,c){if(!0!==c)throw Error("The 'deferred' extender only accepts the value 'true', because it is not supported to turn deferral off once enabled.");b.Hb||(b.Hb=!0,b.ub(function(c){var e,f=!1;return function(){if(!f){a.na.cancel(e);e=a.na.zb(c);try{f=!0,b.notifySubscribers(n,"dirty")}finally{f=
|
||||
!1}}}}))},notify:function(a,c){a.equalityComparer="always"==c?null:K}};var W={undefined:1,"boolean":1,number:1,string:1};a.b("extenders",a.Ta);a.ic=function(b,c,d){this.da=b;this.lc=c;this.mc=d;this.Ib=!1;this.fb=this.Jb=null;a.L(this,"dispose",this.s);a.L(this,"disposeWhenNodeIsRemoved",this.l)};a.ic.prototype.s=function(){this.Ib||(this.fb&&a.a.K.yb(this.Jb,this.fb),this.Ib=!0,this.mc(),this.da=this.lc=this.mc=this.Jb=this.fb=null)};a.ic.prototype.l=function(b){this.Jb=b;a.a.K.za(b,this.fb=this.s.bind(this))};
|
||||
a.T=function(){a.a.Ab(this,D);D.qb(this)};var D={qb:function(a){a.U={change:[]};a.sc=1},subscribe:function(b,c,d){var e=this;d=d||"change";var f=new a.ic(e,c?b.bind(c):b,function(){a.a.Pa(e.U[d],f);e.hb&&e.hb(d)});e.Qa&&e.Qa(d);e.U[d]||(e.U[d]=[]);e.U[d].push(f);return f},notifySubscribers:function(b,c){c=c||"change";"change"===c&&this.Gb();if(this.Wa(c)){var d="change"===c&&this.ed||this.U[c].slice(0);try{a.u.xc();for(var e=0,f;f=d[e];++e)f.Ib||f.lc(b)}finally{a.u.end()}}},ob:function(){return this.sc},
|
||||
Dd:function(a){return this.ob()!==a},Gb:function(){++this.sc},ub:function(b){var c=this,d=a.O(c),e,f,g,h,m;c.gb||(c.gb=c.notifySubscribers,c.notifySubscribers=Z);var k=b(function(){c.Ja=!1;d&&h===c&&(h=c.nc?c.nc():c());var a=f||m&&c.sb(g,h);m=f=e=!1;a&&c.gb(g=h)});c.qc=function(a,b){b&&c.Ja||(m=!b);c.ed=c.U.change.slice(0);c.Ja=e=!0;h=a;k()};c.pc=function(a){e||(g=a,c.gb(a,"beforeChange"))};c.rc=function(){m=!0};c.gd=function(){c.sb(g,c.v(!0))&&(f=!0)}},Wa:function(a){return this.U[a]&&this.U[a].length},
|
||||
Bd:function(b){if(b)return this.U[b]&&this.U[b].length||0;var c=0;a.a.P(this.U,function(a,b){"dirty"!==a&&(c+=b.length)});return c},sb:function(a,c){return!this.equalityComparer||!this.equalityComparer(a,c)},toString:function(){return"[object Object]"},extend:function(b){var c=this;b&&a.a.P(b,function(b,e){var f=a.Ta[b];"function"==typeof f&&(c=f(c,e)||c)});return c}};a.L(D,"init",D.qb);a.L(D,"subscribe",D.subscribe);a.L(D,"extend",D.extend);a.L(D,"getSubscriptionsCount",D.Bd);a.a.Ba&&a.a.setPrototypeOf(D,
|
||||
Function.prototype);a.T.fn=D;a.Qc=function(a){return null!=a&&"function"==typeof a.subscribe&&"function"==typeof a.notifySubscribers};a.b("subscribable",a.T);a.b("isSubscribable",a.Qc);a.S=a.u=function(){function b(a){d.push(e);e=a}function c(){e=d.pop()}var d=[],e,f=0;return{xc:b,end:c,cc:function(b){if(e){if(!a.Qc(b))throw Error("Only subscribable things can act as dependencies");e.od.call(e.pd,b,b.fd||(b.fd=++f))}},G:function(a,d,e){try{return b(),a.apply(d,e||[])}finally{c()}},qa:function(){if(e)return e.o.qa()},
|
||||
Va:function(){if(e)return e.o.Va()},Ya:function(){if(e)return e.Ya},o:function(){if(e)return e.o}}}();a.b("computedContext",a.S);a.b("computedContext.getDependenciesCount",a.S.qa);a.b("computedContext.getDependencies",a.S.Va);a.b("computedContext.isInitial",a.S.Ya);a.b("computedContext.registerDependency",a.S.cc);a.b("ignoreDependencies",a.Yd=a.u.G);var I=a.a.Da("_latestValue");a.ta=function(b){function c(){if(0<arguments.length)return c.sb(c[I],arguments[0])&&(c.ya(),c[I]=arguments[0],c.xa()),this;
|
||||
a.u.cc(c);return c[I]}c[I]=b;a.a.Ba||a.a.extend(c,a.T.fn);a.T.fn.qb(c);a.a.Ab(c,F);a.options.deferUpdates&&a.Ta.deferred(c,!0);return c};var F={equalityComparer:K,v:function(){return this[I]},xa:function(){this.notifySubscribers(this[I],"spectate");this.notifySubscribers(this[I])},ya:function(){this.notifySubscribers(this[I],"beforeChange")}};a.a.Ba&&a.a.setPrototypeOf(F,a.T.fn);var G=a.ta.Ma="__ko_proto__";F[G]=a.ta;a.O=function(b){if((b="function"==typeof b&&b[G])&&b!==F[G]&&b!==a.o.fn[G])throw Error("Invalid object that looks like an observable; possibly from another Knockout instance");
|
||||
return!!b};a.Za=function(b){return"function"==typeof b&&(b[G]===F[G]||b[G]===a.o.fn[G]&&b.Nc)};a.b("observable",a.ta);a.b("isObservable",a.O);a.b("isWriteableObservable",a.Za);a.b("isWritableObservable",a.Za);a.b("observable.fn",F);a.L(F,"peek",F.v);a.L(F,"valueHasMutated",F.xa);a.L(F,"valueWillMutate",F.ya);a.Ha=function(b){b=b||[];if("object"!=typeof b||!("length"in b))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");b=a.ta(b);a.a.Ab(b,
|
||||
a.Ha.fn);return b.extend({trackArrayChanges:!0})};a.Ha.fn={remove:function(b){for(var c=this.v(),d=[],e="function"!=typeof b||a.O(b)?function(a){return a===b}:b,f=0;f<c.length;f++){var g=c[f];if(e(g)){0===d.length&&this.ya();if(c[f]!==g)throw Error("Array modified during remove; cannot remove item");d.push(g);c.splice(f,1);f--}}d.length&&this.xa();return d},removeAll:function(b){if(b===n){var c=this.v(),d=c.slice(0);this.ya();c.splice(0,c.length);this.xa();return d}return b?this.remove(function(c){return 0<=
|
||||
a.a.A(b,c)}):[]},destroy:function(b){var c=this.v(),d="function"!=typeof b||a.O(b)?function(a){return a===b}:b;this.ya();for(var e=c.length-1;0<=e;e--){var f=c[e];d(f)&&(f._destroy=!0)}this.xa()},destroyAll:function(b){return b===n?this.destroy(function(){return!0}):b?this.destroy(function(c){return 0<=a.a.A(b,c)}):[]},indexOf:function(b){var c=this();return a.a.A(c,b)},replace:function(a,c){var d=this.indexOf(a);0<=d&&(this.ya(),this.v()[d]=c,this.xa())},sorted:function(a){var c=this().slice(0);
|
||||
return a?c.sort(a):c.sort()},reversed:function(){return this().slice(0).reverse()}};a.a.Ba&&a.a.setPrototypeOf(a.Ha.fn,a.ta.fn);a.a.D("pop push reverse shift sort splice unshift".split(" "),function(b){a.Ha.fn[b]=function(){var a=this.v();this.ya();this.zc(a,b,arguments);var d=a[b].apply(a,arguments);this.xa();return d===a?this:d}});a.a.D(["slice"],function(b){a.Ha.fn[b]=function(){var a=this();return a[b].apply(a,arguments)}});a.Pc=function(b){return a.O(b)&&"function"==typeof b.remove&&"function"==
|
||||
typeof b.push};a.b("observableArray",a.Ha);a.b("isObservableArray",a.Pc);a.Ta.trackArrayChanges=function(b,c){function d(){function c(){if(m){var d=[].concat(b.v()||[]),e;if(b.Wa("arrayChange")){if(!f||1<m)f=a.a.Pb(k,d,b.Ob);e=f}k=d;f=null;m=0;e&&e.length&&b.notifySubscribers(e,"arrayChange")}}e?c():(e=!0,h=b.subscribe(function(){++m},null,"spectate"),k=[].concat(b.v()||[]),f=null,g=b.subscribe(c))}b.Ob={};c&&"object"==typeof c&&a.a.extend(b.Ob,c);b.Ob.sparse=!0;if(!b.zc){var e=!1,f=null,g,h,m=0,
|
||||
k,l=b.Qa,p=b.hb;b.Qa=function(a){l&&l.call(b,a);"arrayChange"===a&&d()};b.hb=function(a){p&&p.call(b,a);"arrayChange"!==a||b.Wa("arrayChange")||(g&&g.s(),h&&h.s(),h=g=null,e=!1,k=n)};b.zc=function(b,c,d){function l(a,b,c){return k[k.length]={status:a,value:b,index:c}}if(e&&!m){var k=[],p=b.length,g=d.length,h=0;switch(c){case "push":h=p;case "unshift":for(c=0;c<g;c++)l("added",d[c],h+c);break;case "pop":h=p-1;case "shift":p&&l("deleted",b[h],h);break;case "splice":c=Math.min(Math.max(0,0>d[0]?p+d[0]:
|
||||
d[0]),p);for(var p=1===g?p:Math.min(c+(d[1]||0),p),g=c+g-2,h=Math.max(p,g),U=[],L=[],n=2;c<h;++c,++n)c<p&&L.push(l("deleted",b[c],c)),c<g&&U.push(l("added",d[n],c));a.a.Kc(L,U);break;default:return}f=k}}}};var r=a.a.Da("_state");a.o=a.$=function(b,c,d){function e(){if(0<arguments.length){if("function"===typeof f)f.apply(g.nb,arguments);else throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");return this}g.ra||
|
||||
a.u.cc(e);(g.ka||g.J&&e.Xa())&&e.ha();return g.X}"object"===typeof b?d=b:(d=d||{},b&&(d.read=b));if("function"!=typeof d.read)throw Error("Pass a function that returns the value of the ko.computed");var f=d.write,g={X:n,sa:!0,ka:!0,rb:!1,jc:!1,ra:!1,wb:!1,J:!1,Wc:d.read,nb:c||d.owner,l:d.disposeWhenNodeIsRemoved||d.l||null,Sa:d.disposeWhen||d.Sa,Rb:null,I:{},V:0,Ic:null};e[r]=g;e.Nc="function"===typeof f;a.a.Ba||a.a.extend(e,a.T.fn);a.T.fn.qb(e);a.a.Ab(e,C);d.pure?(g.wb=!0,g.J=!0,a.a.extend(e,da)):
|
||||
d.deferEvaluation&&a.a.extend(e,ea);a.options.deferUpdates&&a.Ta.deferred(e,!0);g.l&&(g.jc=!0,g.l.nodeType||(g.l=null));g.J||d.deferEvaluation||e.ha();g.l&&e.ja()&&a.a.K.za(g.l,g.Rb=function(){e.s()});return e};var C={equalityComparer:K,qa:function(){return this[r].V},Va:function(){var b=[];a.a.P(this[r].I,function(a,d){b[d.Ka]=d.da});return b},Vb:function(b){if(!this[r].V)return!1;var c=this.Va();return-1!==a.a.A(c,b)?!0:!!a.a.Lb(c,function(a){return a.Vb&&a.Vb(b)})},uc:function(a,c,d){if(this[r].wb&&
|
||||
c===this)throw Error("A 'pure' computed must not be called recursively");this[r].I[a]=d;d.Ka=this[r].V++;d.La=c.ob()},Xa:function(){var a,c,d=this[r].I;for(a in d)if(Object.prototype.hasOwnProperty.call(d,a)&&(c=d[a],this.Ia&&c.da.Ja||c.da.Dd(c.La)))return!0},Jd:function(){this.Ia&&!this[r].rb&&this.Ia(!1)},ja:function(){var a=this[r];return a.ka||0<a.V},Rd:function(){this.Ja?this[r].ka&&(this[r].sa=!0):this.Hc()},$c:function(a){if(a.Hb){var c=a.subscribe(this.Jd,this,"dirty"),d=a.subscribe(this.Rd,
|
||||
this);return{da:a,s:function(){c.s();d.s()}}}return a.subscribe(this.Hc,this)},Hc:function(){var b=this,c=b.throttleEvaluation;c&&0<=c?(clearTimeout(this[r].Ic),this[r].Ic=a.a.setTimeout(function(){b.ha(!0)},c)):b.Ia?b.Ia(!0):b.ha(!0)},ha:function(b){var c=this[r],d=c.Sa,e=!1;if(!c.rb&&!c.ra){if(c.l&&!a.a.Sb(c.l)||d&&d()){if(!c.jc){this.s();return}}else c.jc=!1;c.rb=!0;try{e=this.zd(b)}finally{c.rb=!1}return e}},zd:function(b){var c=this[r],d=!1,e=c.wb?n:!c.V,d={qd:this,mb:c.I,Qb:c.V};a.u.xc({pd:d,
|
||||
od:ba,o:this,Ya:e});c.I={};c.V=0;var f=this.yd(c,d);c.V?d=this.sb(c.X,f):(this.s(),d=!0);d&&(c.J?this.Gb():this.notifySubscribers(c.X,"beforeChange"),c.X=f,this.notifySubscribers(c.X,"spectate"),!c.J&&b&&this.notifySubscribers(c.X),this.rc&&this.rc());e&&this.notifySubscribers(c.X,"awake");return d},yd:function(b,c){try{var d=b.Wc;return b.nb?d.call(b.nb):d()}finally{a.u.end(),c.Qb&&!b.J&&a.a.P(c.mb,aa),b.sa=b.ka=!1}},v:function(a){var c=this[r];(c.ka&&(a||!c.V)||c.J&&this.Xa())&&this.ha();return c.X},
|
||||
ub:function(b){a.T.fn.ub.call(this,b);this.nc=function(){this[r].J||(this[r].sa?this.ha():this[r].ka=!1);return this[r].X};this.Ia=function(a){this.pc(this[r].X);this[r].ka=!0;a&&(this[r].sa=!0);this.qc(this,!a)}},s:function(){var b=this[r];!b.J&&b.I&&a.a.P(b.I,function(a,b){b.s&&b.s()});b.l&&b.Rb&&a.a.K.yb(b.l,b.Rb);b.I=n;b.V=0;b.ra=!0;b.sa=!1;b.ka=!1;b.J=!1;b.l=n;b.Sa=n;b.Wc=n;this.Nc||(b.nb=n)}},da={Qa:function(b){var c=this,d=c[r];if(!d.ra&&d.J&&"change"==b){d.J=!1;if(d.sa||c.Xa())d.I=null,d.V=
|
||||
0,c.ha()&&c.Gb();else{var e=[];a.a.P(d.I,function(a,b){e[b.Ka]=a});a.a.D(e,function(a,b){var e=d.I[a],m=c.$c(e.da);m.Ka=b;m.La=e.La;d.I[a]=m});c.Xa()&&c.ha()&&c.Gb()}d.ra||c.notifySubscribers(d.X,"awake")}},hb:function(b){var c=this[r];c.ra||"change"!=b||this.Wa("change")||(a.a.P(c.I,function(a,b){b.s&&(c.I[a]={da:b.da,Ka:b.Ka,La:b.La},b.s())}),c.J=!0,this.notifySubscribers(n,"asleep"))},ob:function(){var b=this[r];b.J&&(b.sa||this.Xa())&&this.ha();return a.T.fn.ob.call(this)}},ea={Qa:function(a){"change"!=
|
||||
a&&"beforeChange"!=a||this.v()}};a.a.Ba&&a.a.setPrototypeOf(C,a.T.fn);var N=a.ta.Ma;C[N]=a.o;a.Oc=function(a){return"function"==typeof a&&a[N]===C[N]};a.Fd=function(b){return a.Oc(b)&&b[r]&&b[r].wb};a.b("computed",a.o);a.b("dependentObservable",a.o);a.b("isComputed",a.Oc);a.b("isPureComputed",a.Fd);a.b("computed.fn",C);a.L(C,"peek",C.v);a.L(C,"dispose",C.s);a.L(C,"isActive",C.ja);a.L(C,"getDependenciesCount",C.qa);a.L(C,"getDependencies",C.Va);a.xb=function(b,c){if("function"===typeof b)return a.o(b,
|
||||
c,{pure:!0});b=a.a.extend({},b);b.pure=!0;return a.o(b,c)};a.b("pureComputed",a.xb);(function(){function b(a,f,g){g=g||new d;a=f(a);if("object"!=typeof a||null===a||a===n||a instanceof RegExp||a instanceof Date||a instanceof String||a instanceof Number||a instanceof Boolean)return a;var h=a instanceof Array?[]:{};g.save(a,h);c(a,function(c){var d=f(a[c]);switch(typeof d){case "boolean":case "number":case "string":case "function":h[c]=d;break;case "object":case "undefined":var l=g.get(d);h[c]=l!==
|
||||
n?l:b(d,f,g)}});return h}function c(a,b){if(a instanceof Array){for(var c=0;c<a.length;c++)b(c);"function"==typeof a.toJSON&&b("toJSON")}else for(c in a)b(c)}function d(){this.keys=[];this.values=[]}a.ad=function(c){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");return b(c,function(b){for(var c=0;a.O(b)&&10>c;c++)b=b();return b})};a.toJSON=function(b,c,d){b=a.ad(b);return a.a.hc(b,c,d)};d.prototype={constructor:d,save:function(b,c){var d=a.a.A(this.keys,
|
||||
b);0<=d?this.values[d]=c:(this.keys.push(b),this.values.push(c))},get:function(b){b=a.a.A(this.keys,b);return 0<=b?this.values[b]:n}}})();a.b("toJS",a.ad);a.b("toJSON",a.toJSON);a.Wd=function(b,c,d){function e(c){var e=a.xb(b,d).extend({ma:"always"}),h=e.subscribe(function(a){a&&(h.s(),c(a))});e.notifySubscribers(e.v());return h}return"function"!==typeof Promise||c?e(c.bind(d)):new Promise(e)};a.b("when",a.Wd);(function(){a.w={M:function(b){switch(a.a.R(b)){case "option":return!0===b.__ko__hasDomDataOptionValue__?
|
||||
a.a.g.get(b,a.c.options.$b):7>=a.a.W?b.getAttributeNode("value")&&b.getAttributeNode("value").specified?b.value:b.text:b.value;case "select":return 0<=b.selectedIndex?a.w.M(b.options[b.selectedIndex]):n;default:return b.value}},cb:function(b,c,d){switch(a.a.R(b)){case "option":"string"===typeof c?(a.a.g.set(b,a.c.options.$b,n),"__ko__hasDomDataOptionValue__"in b&&delete b.__ko__hasDomDataOptionValue__,b.value=c):(a.a.g.set(b,a.c.options.$b,c),b.__ko__hasDomDataOptionValue__=!0,b.value="number"===
|
||||
typeof c?c:"");break;case "select":if(""===c||null===c)c=n;for(var e=-1,f=0,g=b.options.length,h;f<g;++f)if(h=a.w.M(b.options[f]),h==c||""===h&&c===n){e=f;break}if(d||0<=e||c===n&&1<b.size)b.selectedIndex=e,6===a.a.W&&a.a.setTimeout(function(){b.selectedIndex=e},0);break;default:if(null===c||c===n)c="";b.value=c}}}})();a.b("selectExtensions",a.w);a.b("selectExtensions.readValue",a.w.M);a.b("selectExtensions.writeValue",a.w.cb);a.m=function(){function b(b){b=a.a.Db(b);123===b.charCodeAt(0)&&(b=b.slice(1,
|
||||
-1));b+="\n,";var c=[],d=b.match(e),p,q=[],h=0;if(1<d.length){for(var x=0,B;B=d[x];++x){var u=B.charCodeAt(0);if(44===u){if(0>=h){c.push(p&&q.length?{key:p,value:q.join("")}:{unknown:p||q.join("")});p=h=0;q=[];continue}}else if(58===u){if(!h&&!p&&1===q.length){p=q.pop();continue}}else if(47===u&&1<B.length&&(47===B.charCodeAt(1)||42===B.charCodeAt(1)))continue;else 47===u&&x&&1<B.length?(u=d[x-1].match(f))&&!g[u[0]]&&(b=b.substr(b.indexOf(B)+1),d=b.match(e),x=-1,B="/"):40===u||123===u||91===u?++h:
|
||||
41===u||125===u||93===u?--h:p||q.length||34!==u&&39!==u||(B=B.slice(1,-1));q.push(B)}if(0<h)throw Error("Unbalanced parentheses, braces, or brackets");}return c}var c=["true","false","null","undefined"],d=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i,e=RegExp("\"(?:\\\\.|[^\"])*\"|'(?:\\\\.|[^'])*'|`(?:\\\\.|[^`])*`|/\\*(?:[^*]|\\*+[^*/])*\\*+/|//.*\n|/(?:\\\\.|[^/])+/w*|[^\\s:,/][^,\"'`{}()/:[\\]]*[^\\s,\"'`{}()/:[\\]]|[^\\s]","g"),f=/[\])"'A-Za-z0-9_$]+$/,g={"in":1,"return":1,"typeof":1},
|
||||
h={};return{Ra:[],wa:h,ac:b,vb:function(e,f){function l(b,e){var f;if(!x){var k=a.getBindingHandler(b);if(k&&k.preprocess&&!(e=k.preprocess(e,b,l)))return;if(k=h[b])f=e,0<=a.a.A(c,f)?f=!1:(k=f.match(d),f=null===k?!1:k[1]?"Object("+k[1]+")"+k[2]:f),k=f;k&&q.push("'"+("string"==typeof h[b]?h[b]:b)+"':function(_z){"+f+"=_z}")}g&&(e="function(){return "+e+" }");p.push("'"+b+"':"+e)}f=f||{};var p=[],q=[],g=f.valueAccessors,x=f.bindingParams,B="string"===typeof e?b(e):e;a.a.D(B,function(a){l(a.key||a.unknown,
|
||||
a.value)});q.length&&l("_ko_property_writers","{"+q.join(",")+" }");return p.join(",")},Id:function(a,b){for(var c=0;c<a.length;c++)if(a[c].key==b)return!0;return!1},eb:function(b,c,d,e,f){if(b&&a.O(b))!a.Za(b)||f&&b.v()===e||b(e);else if((b=c.get("_ko_property_writers"))&&b[d])b[d](e)}}}();a.b("expressionRewriting",a.m);a.b("expressionRewriting.bindingRewriteValidators",a.m.Ra);a.b("expressionRewriting.parseObjectLiteral",a.m.ac);a.b("expressionRewriting.preProcessBindings",a.m.vb);a.b("expressionRewriting._twoWayBindings",
|
||||
a.m.wa);a.b("jsonExpressionRewriting",a.m);a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",a.m.vb);(function(){function b(a){return 8==a.nodeType&&g.test(f?a.text:a.nodeValue)}function c(a){return 8==a.nodeType&&h.test(f?a.text:a.nodeValue)}function d(d,e){for(var f=d,h=1,g=[];f=f.nextSibling;){if(c(f)&&(a.a.g.set(f,k,!0),h--,0===h))return g;g.push(f);b(f)&&h++}if(!e)throw Error("Cannot find closing comment tag to match: "+d.nodeValue);return null}function e(a,b){var c=d(a,b);return c?
|
||||
0<c.length?c[c.length-1].nextSibling:a.nextSibling:null}var f=w&&"\x3c!--test--\x3e"===w.createComment("test").text,g=f?/^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/:/^\s*ko(?:\s+([\s\S]+))?\s*$/,h=f?/^\x3c!--\s*\/ko\s*--\x3e$/:/^\s*\/ko\s*$/,m={ul:!0,ol:!0},k="__ko_matchedEndComment__";a.h={ea:{},childNodes:function(a){return b(a)?d(a):a.childNodes},Ea:function(c){if(b(c)){c=a.h.childNodes(c);for(var d=0,e=c.length;d<e;d++)a.removeNode(c[d])}else a.a.Tb(c)},va:function(c,d){if(b(c)){a.h.Ea(c);for(var e=
|
||||
c.nextSibling,f=0,k=d.length;f<k;f++)e.parentNode.insertBefore(d[f],e)}else a.a.va(c,d)},Vc:function(a,c){var d;b(a)?(d=a.nextSibling,a=a.parentNode):d=a.firstChild;d?c!==d&&a.insertBefore(c,d):a.appendChild(c)},Wb:function(c,d,e){e?(e=e.nextSibling,b(c)&&(c=c.parentNode),e?d!==e&&c.insertBefore(d,e):c.appendChild(d)):a.h.Vc(c,d)},firstChild:function(a){if(b(a))return!a.nextSibling||c(a.nextSibling)?null:a.nextSibling;if(a.firstChild&&c(a.firstChild))throw Error("Found invalid end comment, as the first child of "+
|
||||
a);return a.firstChild},nextSibling:function(d){b(d)&&(d=e(d));if(d.nextSibling&&c(d.nextSibling)){var f=d.nextSibling;if(c(f)&&!a.a.g.get(f,k))throw Error("Found end comment without a matching opening comment, as child of "+d);return null}return d.nextSibling},Cd:b,Vd:function(a){return(a=(f?a.text:a.nodeValue).match(g))?a[1]:null},Sc:function(d){if(m[a.a.R(d)]){var f=d.firstChild;if(f){do if(1===f.nodeType){var k;k=f.firstChild;var h=null;if(k){do if(h)h.push(k);else if(b(k)){var g=e(k,!0);g?k=
|
||||
g:h=[k]}else c(k)&&(h=[k]);while(k=k.nextSibling)}if(k=h)for(h=f.nextSibling,g=0;g<k.length;g++)h?d.insertBefore(k[g],h):d.appendChild(k[g])}while(f=f.nextSibling)}}}}})();a.b("virtualElements",a.h);a.b("virtualElements.allowedBindings",a.h.ea);a.b("virtualElements.emptyNode",a.h.Ea);a.b("virtualElements.insertAfter",a.h.Wb);a.b("virtualElements.prepend",a.h.Vc);a.b("virtualElements.setDomNodeChildren",a.h.va);(function(){a.ga=function(){this.nd={}};a.a.extend(a.ga.prototype,{nodeHasBindings:function(b){switch(b.nodeType){case 1:return null!=
|
||||
b.getAttribute("data-bind")||a.j.getComponentNameForNode(b);case 8:return a.h.Cd(b);default:return!1}},getBindings:function(b,c){var d=this.getBindingsString(b,c),d=d?this.parseBindingsString(d,c,b):null;return a.j.tc(d,b,c,!1)},getBindingAccessors:function(b,c){var d=this.getBindingsString(b,c),d=d?this.parseBindingsString(d,c,b,{valueAccessors:!0}):null;return a.j.tc(d,b,c,!0)},getBindingsString:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind");case 8:return a.h.Vd(b);default:return null}},
|
||||
parseBindingsString:function(b,c,d,e){try{var f=this.nd,g=b+(e&&e.valueAccessors||""),h;if(!(h=f[g])){var m,k="with($context){with($data||{}){return{"+a.m.vb(b,e)+"}}}";m=new Function("$context","$element",k);h=f[g]=m}return h(c,d)}catch(l){throw l.message="Unable to parse bindings.\nBindings value: "+b+"\nMessage: "+l.message,l;}}});a.ga.instance=new a.ga})();a.b("bindingProvider",a.ga);(function(){function b(b){var c=(b=a.a.g.get(b,z))&&b.N;c&&(b.N=null,c.Tc())}function c(c,d,e){this.node=c;this.yc=
|
||||
d;this.kb=[];this.H=!1;d.N||a.a.K.za(c,b);e&&e.N&&(e.N.kb.push(c),this.Kb=e)}function d(a){return function(){return a}}function e(a){return a()}function f(b){return a.a.Ga(a.u.G(b),function(a,c){return function(){return b()[c]}})}function g(b,c,e){return"function"===typeof b?f(b.bind(null,c,e)):a.a.Ga(b,d)}function h(a,b){return f(this.getBindings.bind(this,a,b))}function m(b,c){var d=a.h.firstChild(c);if(d){var e,f=a.ga.instance,l=f.preprocessNode;if(l){for(;e=d;)d=a.h.nextSibling(e),l.call(f,e);
|
||||
d=a.h.firstChild(c)}for(;e=d;)d=a.h.nextSibling(e),k(b,e)}a.i.ma(c,a.i.H)}function k(b,c){var d=b,e=1===c.nodeType;e&&a.h.Sc(c);if(e||a.ga.instance.nodeHasBindings(c))d=p(c,null,b).bindingContextForDescendants;d&&!u[a.a.R(c)]&&m(d,c)}function l(b){var c=[],d={},e=[];a.a.P(b,function ca(f){if(!d[f]){var k=a.getBindingHandler(f);k&&(k.after&&(e.push(f),a.a.D(k.after,function(c){if(b[c]){if(-1!==a.a.A(e,c))throw Error("Cannot combine the following bindings, because they have a cyclic dependency: "+e.join(", "));
|
||||
ca(c)}}),e.length--),c.push({key:f,Mc:k}));d[f]=!0}});return c}function p(b,c,d){var f=a.a.g.Ub(b,z,{}),k=f.hd;if(!c){if(k)throw Error("You cannot apply bindings multiple times to the same element.");f.hd=!0}k||(f.context=d);f.Zb||(f.Zb={});var g;if(c&&"function"!==typeof c)g=c;else{var p=a.ga.instance,q=p.getBindingAccessors||h,m=a.$(function(){if(g=c?c(d,b):q.call(p,b,d)){if(d[t])d[t]();if(d[B])d[B]()}return g},null,{l:b});g&&m.ja()||(m=null)}var x=d,u;if(g){var J=function(){return a.a.Ga(m?m():
|
||||
g,e)},r=m?function(a){return function(){return e(m()[a])}}:function(a){return g[a]};J.get=function(a){return g[a]&&e(r(a))};J.has=function(a){return a in g};a.i.H in g&&a.i.subscribe(b,a.i.H,function(){var c=(0,g[a.i.H])();if(c){var d=a.h.childNodes(b);d.length&&c(d,a.Ec(d[0]))}});a.i.pa in g&&(x=a.i.Cb(b,d),a.i.subscribe(b,a.i.pa,function(){var c=(0,g[a.i.pa])();c&&a.h.firstChild(b)&&c(b)}));f=l(g);a.a.D(f,function(c){var d=c.Mc.init,e=c.Mc.update,f=c.key;if(8===b.nodeType&&!a.h.ea[f])throw Error("The binding '"+
|
||||
f+"' cannot be used with virtual elements");try{"function"==typeof d&&a.u.G(function(){var a=d(b,r(f),J,x.$data,x);if(a&&a.controlsDescendantBindings){if(u!==n)throw Error("Multiple bindings ("+u+" and "+f+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");u=f}}),"function"==typeof e&&a.$(function(){e(b,r(f),J,x.$data,x)},null,{l:b})}catch(k){throw k.message='Unable to process binding "'+f+": "+g[f]+'"\nMessage: '+k.message,
|
||||
k;}})}f=u===n;return{shouldBindDescendants:f,bindingContextForDescendants:f&&x}}function q(b,c){return b&&b instanceof a.fa?b:new a.fa(b,n,n,c)}var t=a.a.Da("_subscribable"),x=a.a.Da("_ancestorBindingInfo"),B=a.a.Da("_dataDependency");a.c={};var u={script:!0,textarea:!0,template:!0};a.getBindingHandler=function(b){return a.c[b]};var J={};a.fa=function(b,c,d,e,f){function k(){var b=p?h():h,f=a.a.f(b);c?(a.a.extend(l,c),x in c&&(l[x]=c[x])):(l.$parents=[],l.$root=f,l.ko=a);l[t]=q;g?f=l.$data:(l.$rawData=
|
||||
b,l.$data=f);d&&(l[d]=f);e&&e(l,c,f);if(c&&c[t]&&!a.S.o().Vb(c[t]))c[t]();m&&(l[B]=m);return l.$data}var l=this,g=b===J,h=g?n:b,p="function"==typeof h&&!a.O(h),q,m=f&&f.dataDependency;f&&f.exportDependencies?k():(q=a.xb(k),q.v(),q.ja()?q.equalityComparer=null:l[t]=n)};a.fa.prototype.createChildContext=function(b,c,d,e){!e&&c&&"object"==typeof c&&(e=c,c=e.as,d=e.extend);if(c&&e&&e.noChildContext){var f="function"==typeof b&&!a.O(b);return new a.fa(J,this,null,function(a){d&&d(a);a[c]=f?b():b},e)}return new a.fa(b,
|
||||
this,c,function(a,b){a.$parentContext=b;a.$parent=b.$data;a.$parents=(b.$parents||[]).slice(0);a.$parents.unshift(a.$parent);d&&d(a)},e)};a.fa.prototype.extend=function(b,c){return new a.fa(J,this,null,function(c){a.a.extend(c,"function"==typeof b?b(c):b)},c)};var z=a.a.g.Z();c.prototype.Tc=function(){this.Kb&&this.Kb.N&&this.Kb.N.sd(this.node)};c.prototype.sd=function(b){a.a.Pa(this.kb,b);!this.kb.length&&this.H&&this.Cc()};c.prototype.Cc=function(){this.H=!0;this.yc.N&&!this.kb.length&&(this.yc.N=
|
||||
null,a.a.K.yb(this.node,b),a.i.ma(this.node,a.i.pa),this.Tc())};a.i={H:"childrenComplete",pa:"descendantsComplete",subscribe:function(b,c,d,e,f){var k=a.a.g.Ub(b,z,{});k.Fa||(k.Fa=new a.T);f&&f.notifyImmediately&&k.Zb[c]&&a.u.G(d,e,[b]);return k.Fa.subscribe(d,e,c)},ma:function(b,c){var d=a.a.g.get(b,z);if(d&&(d.Zb[c]=!0,d.Fa&&d.Fa.notifySubscribers(b,c),c==a.i.H))if(d.N)d.N.Cc();else if(d.N===n&&d.Fa&&d.Fa.Wa(a.i.pa))throw Error("descendantsComplete event not supported for bindings on this node");
|
||||
},Cb:function(b,d){var e=a.a.g.Ub(b,z,{});e.N||(e.N=new c(b,e,d[x]));return d[x]==e?d:d.extend(function(a){a[x]=e})}};a.Td=function(b){return(b=a.a.g.get(b,z))&&b.context};a.ib=function(b,c,d){1===b.nodeType&&a.h.Sc(b);return p(b,c,q(d))};a.ld=function(b,c,d){d=q(d);return a.ib(b,g(c,d,b),d)};a.Oa=function(a,b){1!==b.nodeType&&8!==b.nodeType||m(q(a),b)};a.vc=function(a,b,c){!v&&A.jQuery&&(v=A.jQuery);if(2>arguments.length){if(b=w.body,!b)throw Error("ko.applyBindings: could not find document.body; has the document been loaded?");
|
||||
}else if(!b||1!==b.nodeType&&8!==b.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");k(q(a,c),b)};a.Dc=function(b){return!b||1!==b.nodeType&&8!==b.nodeType?n:a.Td(b)};a.Ec=function(b){return(b=a.Dc(b))?b.$data:n};a.b("bindingHandlers",a.c);a.b("bindingEvent",a.i);a.b("bindingEvent.subscribe",a.i.subscribe);a.b("bindingEvent.startPossiblyAsyncContentBinding",a.i.Cb);a.b("applyBindings",a.vc);a.b("applyBindingsToDescendants",a.Oa);
|
||||
a.b("applyBindingAccessorsToNode",a.ib);a.b("applyBindingsToNode",a.ld);a.b("contextFor",a.Dc);a.b("dataFor",a.Ec)})();(function(b){function c(c,e){var k=Object.prototype.hasOwnProperty.call(f,c)?f[c]:b,l;k?k.subscribe(e):(k=f[c]=new a.T,k.subscribe(e),d(c,function(b,d){var e=!(!d||!d.synchronous);g[c]={definition:b,Gd:e};delete f[c];l||e?k.notifySubscribers(b):a.na.zb(function(){k.notifySubscribers(b)})}),l=!0)}function d(a,b){e("getConfig",[a],function(c){c?e("loadComponent",[a,c],function(a){b(a,
|
||||
c)}):b(null,null)})}function e(c,d,f,l){l||(l=a.j.loaders.slice(0));var g=l.shift();if(g){var q=g[c];if(q){var t=!1;if(q.apply(g,d.concat(function(a){t?f(null):null!==a?f(a):e(c,d,f,l)}))!==b&&(t=!0,!g.suppressLoaderExceptions))throw Error("Component loaders must supply values by invoking the callback, not by returning values synchronously.");}else e(c,d,f,l)}else f(null)}var f={},g={};a.j={get:function(d,e){var f=Object.prototype.hasOwnProperty.call(g,d)?g[d]:b;f?f.Gd?a.u.G(function(){e(f.definition)}):
|
||||
a.na.zb(function(){e(f.definition)}):c(d,e)},Bc:function(a){delete g[a]},oc:e};a.j.loaders=[];a.b("components",a.j);a.b("components.get",a.j.get);a.b("components.clearCachedDefinition",a.j.Bc)})();(function(){function b(b,c,d,e){function g(){0===--B&&e(h)}var h={},B=2,u=d.template;d=d.viewModel;u?f(c,u,function(c){a.j.oc("loadTemplate",[b,c],function(a){h.template=a;g()})}):g();d?f(c,d,function(c){a.j.oc("loadViewModel",[b,c],function(a){h[m]=a;g()})}):g()}function c(a,b,d){if("function"===typeof b)d(function(a){return new b(a)});
|
||||
else if("function"===typeof b[m])d(b[m]);else if("instance"in b){var e=b.instance;d(function(){return e})}else"viewModel"in b?c(a,b.viewModel,d):a("Unknown viewModel value: "+b)}function d(b){switch(a.a.R(b)){case "script":return a.a.ua(b.text);case "textarea":return a.a.ua(b.value);case "template":if(e(b.content))return a.a.Ca(b.content.childNodes)}return a.a.Ca(b.childNodes)}function e(a){return A.DocumentFragment?a instanceof DocumentFragment:a&&11===a.nodeType}function f(a,b,c){"string"===typeof b.require?
|
||||
T||A.require?(T||A.require)([b.require],function(a){a&&"object"===typeof a&&a.Xd&&a["default"]&&(a=a["default"]);c(a)}):a("Uses require, but no AMD loader is present"):c(b)}function g(a){return function(b){throw Error("Component '"+a+"': "+b);}}var h={};a.j.register=function(b,c){if(!c)throw Error("Invalid configuration for "+b);if(a.j.tb(b))throw Error("Component "+b+" is already registered");h[b]=c};a.j.tb=function(a){return Object.prototype.hasOwnProperty.call(h,a)};a.j.unregister=function(b){delete h[b];
|
||||
a.j.Bc(b)};a.j.Fc={getConfig:function(b,c){c(a.j.tb(b)?h[b]:null)},loadComponent:function(a,c,d){var e=g(a);f(e,c,function(c){b(a,e,c,d)})},loadTemplate:function(b,c,f){b=g(b);if("string"===typeof c)f(a.a.ua(c));else if(c instanceof Array)f(c);else if(e(c))f(a.a.la(c.childNodes));else if(c.element)if(c=c.element,A.HTMLElement?c instanceof HTMLElement:c&&c.tagName&&1===c.nodeType)f(d(c));else if("string"===typeof c){var h=w.getElementById(c);h?f(d(h)):b("Cannot find element with ID "+c)}else b("Unknown element type: "+
|
||||
c);else b("Unknown template value: "+c)},loadViewModel:function(a,b,d){c(g(a),b,d)}};var m="createViewModel";a.b("components.register",a.j.register);a.b("components.isRegistered",a.j.tb);a.b("components.unregister",a.j.unregister);a.b("components.defaultLoader",a.j.Fc);a.j.loaders.push(a.j.Fc);a.j.dd=h})();(function(){function b(b,e){var f=b.getAttribute("params");if(f){var f=c.parseBindingsString(f,e,b,{valueAccessors:!0,bindingParams:!0}),f=a.a.Ga(f,function(c){return a.o(c,null,{l:b})}),g=a.a.Ga(f,
|
||||
function(c){var e=c.v();return c.ja()?a.o({read:function(){return a.a.f(c())},write:a.Za(e)&&function(a){c()(a)},l:b}):e});Object.prototype.hasOwnProperty.call(g,"$raw")||(g.$raw=f);return g}return{$raw:{}}}a.j.getComponentNameForNode=function(b){var c=a.a.R(b);if(a.j.tb(c)&&(-1!=c.indexOf("-")||"[object HTMLUnknownElement]"==""+b||8>=a.a.W&&b.tagName===c))return c};a.j.tc=function(c,e,f,g){if(1===e.nodeType){var h=a.j.getComponentNameForNode(e);if(h){c=c||{};if(c.component)throw Error('Cannot use the "component" binding on a custom element matching a component');
|
||||
var m={name:h,params:b(e,f)};c.component=g?function(){return m}:m}}return c};var c=new a.ga;9>a.a.W&&(a.j.register=function(a){return function(b){return a.apply(this,arguments)}}(a.j.register),w.createDocumentFragment=function(b){return function(){var c=b(),f=a.j.dd,g;for(g in f);return c}}(w.createDocumentFragment))})();(function(){function b(b,c,d){c=c.template;if(!c)throw Error("Component '"+b+"' has no template");b=a.a.Ca(c);a.h.va(d,b)}function c(a,b,c){var d=a.createViewModel;return d?d.call(a,
|
||||
b,c):b}var d=0;a.c.component={init:function(e,f,g,h,m){function k(){var a=l&&l.dispose;"function"===typeof a&&a.call(l);q&&q.s();p=l=q=null}var l,p,q,t=a.a.la(a.h.childNodes(e));a.h.Ea(e);a.a.K.za(e,k);a.o(function(){var g=a.a.f(f()),h,u;"string"===typeof g?h=g:(h=a.a.f(g.name),u=a.a.f(g.params));if(!h)throw Error("No component name specified");var n=a.i.Cb(e,m),z=p=++d;a.j.get(h,function(d){if(p===z){k();if(!d)throw Error("Unknown component '"+h+"'");b(h,d,e);var f=c(d,u,{element:e,templateNodes:t});
|
||||
d=n.createChildContext(f,{extend:function(a){a.$component=f;a.$componentTemplateNodes=t}});f&&f.koDescendantsComplete&&(q=a.i.subscribe(e,a.i.pa,f.koDescendantsComplete,f));l=f;a.Oa(d,e)}})},null,{l:e});return{controlsDescendantBindings:!0}}};a.h.ea.component=!0})();var V={"class":"className","for":"htmlFor"};a.c.attr={update:function(b,c){var d=a.a.f(c())||{};a.a.P(d,function(c,d){d=a.a.f(d);var g=c.indexOf(":"),g="lookupNamespaceURI"in b&&0<g&&b.lookupNamespaceURI(c.substr(0,g)),h=!1===d||null===
|
||||
d||d===n;h?g?b.removeAttributeNS(g,c):b.removeAttribute(c):d=d.toString();8>=a.a.W&&c in V?(c=V[c],h?b.removeAttribute(c):b[c]=d):h||(g?b.setAttributeNS(g,c,d):b.setAttribute(c,d));"name"===c&&a.a.Yc(b,h?"":d)})}};(function(){a.c.checked={after:["value","attr"],init:function(b,c,d){function e(){var e=b.checked,f=g();if(!a.S.Ya()&&(e||!m&&!a.S.qa())){var k=a.u.G(c);if(l){var q=p?k.v():k,z=t;t=f;z!==f?e&&(a.a.Na(q,f,!0),a.a.Na(q,z,!1)):a.a.Na(q,f,e);p&&a.Za(k)&&k(q)}else h&&(f===n?f=e:e||(f=n)),a.m.eb(k,
|
||||
d,"checked",f,!0)}}function f(){var d=a.a.f(c()),e=g();l?(b.checked=0<=a.a.A(d,e),t=e):b.checked=h&&e===n?!!d:g()===d}var g=a.xb(function(){if(d.has("checkedValue"))return a.a.f(d.get("checkedValue"));if(q)return d.has("value")?a.a.f(d.get("value")):b.value}),h="checkbox"==b.type,m="radio"==b.type;if(h||m){var k=c(),l=h&&a.a.f(k)instanceof Array,p=!(l&&k.push&&k.splice),q=m||l,t=l?g():n;m&&!b.name&&a.c.uniqueName.init(b,function(){return!0});a.o(e,null,{l:b});a.a.B(b,"click",e);a.o(f,null,{l:b});
|
||||
k=n}}};a.m.wa.checked=!0;a.c.checkedValue={update:function(b,c){b.value=a.a.f(c())}}})();a.c["class"]={update:function(b,c){var d=a.a.Db(a.a.f(c()));a.a.Eb(b,b.__ko__cssValue,!1);b.__ko__cssValue=d;a.a.Eb(b,d,!0)}};a.c.css={update:function(b,c){var d=a.a.f(c());null!==d&&"object"==typeof d?a.a.P(d,function(c,d){d=a.a.f(d);a.a.Eb(b,c,d)}):a.c["class"].update(b,c)}};a.c.enable={update:function(b,c){var d=a.a.f(c());d&&b.disabled?b.removeAttribute("disabled"):d||b.disabled||(b.disabled=!0)}};a.c.disable=
|
||||
{update:function(b,c){a.c.enable.update(b,function(){return!a.a.f(c())})}};a.c.event={init:function(b,c,d,e,f){var g=c()||{};a.a.P(g,function(g){"string"==typeof g&&a.a.B(b,g,function(b){var k,l=c()[g];if(l){try{var p=a.a.la(arguments);e=f.$data;p.unshift(e);k=l.apply(e,p)}finally{!0!==k&&(b.preventDefault?b.preventDefault():b.returnValue=!1)}!1===d.get(g+"Bubble")&&(b.cancelBubble=!0,b.stopPropagation&&b.stopPropagation())}})})}};a.c.foreach={Rc:function(b){return function(){var c=b(),d=a.a.bc(c);
|
||||
if(!d||"number"==typeof d.length)return{foreach:c,templateEngine:a.ba.Ma};a.a.f(c);return{foreach:d.data,as:d.as,noChildContext:d.noChildContext,includeDestroyed:d.includeDestroyed,afterAdd:d.afterAdd,beforeRemove:d.beforeRemove,afterRender:d.afterRender,beforeMove:d.beforeMove,afterMove:d.afterMove,templateEngine:a.ba.Ma}}},init:function(b,c){return a.c.template.init(b,a.c.foreach.Rc(c))},update:function(b,c,d,e,f){return a.c.template.update(b,a.c.foreach.Rc(c),d,e,f)}};a.m.Ra.foreach=!1;a.h.ea.foreach=
|
||||
!0;a.c.hasfocus={init:function(b,c,d){function e(e){b.__ko_hasfocusUpdating=!0;var f=b.ownerDocument;if("activeElement"in f){var g;try{g=f.activeElement}catch(l){g=f.body}e=g===b}f=c();a.m.eb(f,d,"hasfocus",e,!0);b.__ko_hasfocusLastValue=e;b.__ko_hasfocusUpdating=!1}var f=e.bind(null,!0),g=e.bind(null,!1);a.a.B(b,"focus",f);a.a.B(b,"focusin",f);a.a.B(b,"blur",g);a.a.B(b,"focusout",g);b.__ko_hasfocusLastValue=!1},update:function(b,c){var d=!!a.a.f(c());b.__ko_hasfocusUpdating||b.__ko_hasfocusLastValue===
|
||||
d||(d?b.focus():b.blur(),!d&&b.__ko_hasfocusLastValue&&b.ownerDocument.body.focus(),a.u.G(a.a.Fb,null,[b,d?"focusin":"focusout"]))}};a.m.wa.hasfocus=!0;a.c.hasFocus=a.c.hasfocus;a.m.wa.hasFocus="hasfocus";a.c.html={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.fc(b,c())}};(function(){function b(b,d,e){a.c[b]={init:function(b,c,h,m,k){var l,p,q={},t,x,n;if(d){m=h.get("as");var u=h.get("noChildContext");n=!(m&&u);q={as:m,noChildContext:u,exportDependencies:n}}x=(t=
|
||||
"render"==h.get("completeOn"))||h.has(a.i.pa);a.o(function(){var h=a.a.f(c()),m=!e!==!h,u=!p,r;if(n||m!==l){x&&(k=a.i.Cb(b,k));if(m){if(!d||n)q.dataDependency=a.S.o();r=d?k.createChildContext("function"==typeof h?h:c,q):a.S.qa()?k.extend(null,q):k}u&&a.S.qa()&&(p=a.a.Ca(a.h.childNodes(b),!0));m?(u||a.h.va(b,a.a.Ca(p)),a.Oa(r,b)):(a.h.Ea(b),t||a.i.ma(b,a.i.H));l=m}},null,{l:b});return{controlsDescendantBindings:!0}}};a.m.Ra[b]=!1;a.h.ea[b]=!0}b("if");b("ifnot",!1,!0);b("with",!0)})();a.c.let={init:function(b,
|
||||
c,d,e,f){c=f.extend(c);a.Oa(c,b);return{controlsDescendantBindings:!0}}};a.h.ea.let=!0;var Q={};a.c.options={init:function(b){if("select"!==a.a.R(b))throw Error("options binding applies only to SELECT elements");for(;0<b.length;)b.remove(0);return{controlsDescendantBindings:!0}},update:function(b,c,d){function e(){return a.a.jb(b.options,function(a){return a.selected})}function f(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[b]:c}function g(c,d){if(x&&l)a.i.ma(b,a.i.H);else if(t.length){var e=
|
||||
0<=a.a.A(t,a.w.M(d[0]));a.a.Zc(d[0],e);x&&!e&&a.u.G(a.a.Fb,null,[b,"change"])}}var h=b.multiple,m=0!=b.length&&h?b.scrollTop:null,k=a.a.f(c()),l=d.get("valueAllowUnset")&&d.has("value"),p=d.get("optionsIncludeDestroyed");c={};var q,t=[];l||(h?t=a.a.Mb(e(),a.w.M):0<=b.selectedIndex&&t.push(a.w.M(b.options[b.selectedIndex])));k&&("undefined"==typeof k.length&&(k=[k]),q=a.a.jb(k,function(b){return p||b===n||null===b||!a.a.f(b._destroy)}),d.has("optionsCaption")&&(k=a.a.f(d.get("optionsCaption")),null!==
|
||||
k&&k!==n&&q.unshift(Q)));var x=!1;c.beforeRemove=function(a){b.removeChild(a)};k=g;d.has("optionsAfterRender")&&"function"==typeof d.get("optionsAfterRender")&&(k=function(b,c){g(0,c);a.u.G(d.get("optionsAfterRender"),null,[c[0],b!==Q?b:n])});a.a.ec(b,q,function(c,e,g){g.length&&(t=!l&&g[0].selected?[a.w.M(g[0])]:[],x=!0);e=b.ownerDocument.createElement("option");c===Q?(a.a.Bb(e,d.get("optionsCaption")),a.w.cb(e,n)):(g=f(c,d.get("optionsValue"),c),a.w.cb(e,a.a.f(g)),c=f(c,d.get("optionsText"),g),
|
||||
a.a.Bb(e,c));return[e]},c,k);if(!l){var B;h?B=t.length&&e().length<t.length:B=t.length&&0<=b.selectedIndex?a.w.M(b.options[b.selectedIndex])!==t[0]:t.length||0<=b.selectedIndex;B&&a.u.G(a.a.Fb,null,[b,"change"])}(l||a.S.Ya())&&a.i.ma(b,a.i.H);a.a.wd(b);m&&20<Math.abs(m-b.scrollTop)&&(b.scrollTop=m)}};a.c.options.$b=a.a.g.Z();a.c.selectedOptions={init:function(b,c,d){function e(){var e=c(),f=[];a.a.D(b.getElementsByTagName("option"),function(b){b.selected&&f.push(a.w.M(b))});a.m.eb(e,d,"selectedOptions",
|
||||
f)}function f(){var d=a.a.f(c()),e=b.scrollTop;d&&"number"==typeof d.length&&a.a.D(b.getElementsByTagName("option"),function(b){var c=0<=a.a.A(d,a.w.M(b));b.selected!=c&&a.a.Zc(b,c)});b.scrollTop=e}if("select"!=a.a.R(b))throw Error("selectedOptions binding applies only to SELECT elements");var g;a.i.subscribe(b,a.i.H,function(){g?e():(a.a.B(b,"change",e),g=a.o(f,null,{l:b}))},null,{notifyImmediately:!0})},update:function(){}};a.m.wa.selectedOptions=!0;a.c.style={update:function(b,c){var d=a.a.f(c()||
|
||||
{});a.a.P(d,function(c,d){d=a.a.f(d);if(null===d||d===n||!1===d)d="";if(v)v(b).css(c,d);else if(/^--/.test(c))b.style.setProperty(c,d);else{c=c.replace(/-(\w)/g,function(a,b){return b.toUpperCase()});var g=b.style[c];b.style[c]=d;d===g||b.style[c]!=g||isNaN(d)||(b.style[c]=d+"px")}})}};a.c.submit={init:function(b,c,d,e,f){if("function"!=typeof c())throw Error("The value for a submit binding must be a function");a.a.B(b,"submit",function(a){var d,e=c();try{d=e.call(f.$data,b)}finally{!0!==d&&(a.preventDefault?
|
||||
a.preventDefault():a.returnValue=!1)}})}};a.c.text={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Bb(b,c())}};a.h.ea.text=!0;(function(){if(A&&A.navigator){var b=function(a){if(a)return parseFloat(a[1])},c=A.navigator.userAgent,d,e,f,g,h;(d=A.opera&&A.opera.version&&parseInt(A.opera.version()))||(h=b(c.match(/Edge\/([^ ]+)$/)))||b(c.match(/Chrome\/([^ ]+)/))||(e=b(c.match(/Version\/([^ ]+) Safari/)))||(f=b(c.match(/Firefox\/([^ ]+)/)))||(g=a.a.W||b(c.match(/MSIE ([^ ]+)/)))||
|
||||
(g=b(c.match(/rv:([^ )]+)/)))}if(8<=g&&10>g)var m=a.a.g.Z(),k=a.a.g.Z(),l=function(b){var c=this.activeElement;(c=c&&a.a.g.get(c,k))&&c(b)},p=function(b,c){var d=b.ownerDocument;a.a.g.get(d,m)||(a.a.g.set(d,m,!0),a.a.B(d,"selectionchange",l));a.a.g.set(b,k,c)};a.c.textInput={init:function(b,c,k){function l(c,d){a.a.B(b,c,d)}function m(){var d=a.a.f(c());if(null===d||d===n)d="";L!==n&&d===L?a.a.setTimeout(m,4):b.value!==d&&(y=!0,b.value=d,y=!1,v=b.value)}function r(){w||(L=b.value,w=a.a.setTimeout(z,
|
||||
4))}function z(){clearTimeout(w);L=w=n;var d=b.value;v!==d&&(v=d,a.m.eb(c(),k,"textInput",d))}var v=b.value,w,L,A=9==a.a.W?r:z,y=!1;g&&l("keypress",z);11>g&&l("propertychange",function(a){y||"value"!==a.propertyName||A(a)});8==g&&(l("keyup",z),l("keydown",z));p&&(p(b,A),l("dragend",r));(!g||9<=g)&&l("input",A);5>e&&"textarea"===a.a.R(b)?(l("keydown",r),l("paste",r),l("cut",r)):11>d?l("keydown",r):4>f?(l("DOMAutoComplete",z),l("dragdrop",z),l("drop",z)):h&&"number"===b.type&&l("keydown",r);l("change",
|
||||
z);l("blur",z);a.o(m,null,{l:b})}};a.m.wa.textInput=!0;a.c.textinput={preprocess:function(a,b,c){c("textInput",a)}}})();a.c.uniqueName={init:function(b,c){if(c()){var d="ko_unique_"+ ++a.c.uniqueName.rd;a.a.Yc(b,d)}}};a.c.uniqueName.rd=0;a.c.using={init:function(b,c,d,e,f){var g;d.has("as")&&(g={as:d.get("as"),noChildContext:d.get("noChildContext")});c=f.createChildContext(c,g);a.Oa(c,b);return{controlsDescendantBindings:!0}}};a.h.ea.using=!0;a.c.value={init:function(b,c,d){var e=a.a.R(b),f="input"==
|
||||
e;if(!f||"checkbox"!=b.type&&"radio"!=b.type){var g=[],h=d.get("valueUpdate"),m=!1,k=null;h&&("string"==typeof h?g=[h]:g=a.a.wc(h),a.a.Pa(g,"change"));var l=function(){k=null;m=!1;var e=c(),f=a.w.M(b);a.m.eb(e,d,"value",f)};!a.a.W||!f||"text"!=b.type||"off"==b.autocomplete||b.form&&"off"==b.form.autocomplete||-1!=a.a.A(g,"propertychange")||(a.a.B(b,"propertychange",function(){m=!0}),a.a.B(b,"focus",function(){m=!1}),a.a.B(b,"blur",function(){m&&l()}));a.a.D(g,function(c){var d=l;a.a.Ud(c,"after")&&
|
||||
(d=function(){k=a.w.M(b);a.a.setTimeout(l,0)},c=c.substring(5));a.a.B(b,c,d)});var p;p=f&&"file"==b.type?function(){var d=a.a.f(c());null===d||d===n||""===d?b.value="":a.u.G(l)}:function(){var f=a.a.f(c()),g=a.w.M(b);if(null!==k&&f===k)a.a.setTimeout(p,0);else if(f!==g||g===n)"select"===e?(g=d.get("valueAllowUnset"),a.w.cb(b,f,g),g||f===a.w.M(b)||a.u.G(l)):a.w.cb(b,f)};if("select"===e){var q;a.i.subscribe(b,a.i.H,function(){q?d.get("valueAllowUnset")?p():l():(a.a.B(b,"change",l),q=a.o(p,null,{l:b}))},
|
||||
null,{notifyImmediately:!0})}else a.a.B(b,"change",l),a.o(p,null,{l:b})}else a.ib(b,{checkedValue:c})},update:function(){}};a.m.wa.value=!0;a.c.visible={update:function(b,c){var d=a.a.f(c()),e="none"!=b.style.display;d&&!e?b.style.display="":!d&&e&&(b.style.display="none")}};a.c.hidden={update:function(b,c){a.c.visible.update(b,function(){return!a.a.f(c())})}};(function(b){a.c[b]={init:function(c,d,e,f,g){return a.c.event.init.call(this,c,function(){var a={};a[b]=d();return a},e,f,g)}}})("click");
|
||||
a.ca=function(){};a.ca.prototype.renderTemplateSource=function(){throw Error("Override renderTemplateSource");};a.ca.prototype.createJavaScriptEvaluatorBlock=function(){throw Error("Override createJavaScriptEvaluatorBlock");};a.ca.prototype.makeTemplateSource=function(b,c){if("string"==typeof b){c=c||w;var d=c.getElementById(b);if(!d)throw Error("Cannot find template with ID "+b);return new a.C.F(d)}if(1==b.nodeType||8==b.nodeType)return new a.C.ia(b);throw Error("Unknown template type: "+b);};a.ca.prototype.renderTemplate=
|
||||
function(a,c,d,e){a=this.makeTemplateSource(a,e);return this.renderTemplateSource(a,c,d,e)};a.ca.prototype.isTemplateRewritten=function(a,c){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(a,c).data("isRewritten")};a.ca.prototype.rewriteTemplate=function(a,c,d){a=this.makeTemplateSource(a,d);c=c(a.text());a.text(c);a.data("isRewritten",!0)};a.b("templateEngine",a.ca);a.kc=function(){function b(b,c,d,h){b=a.m.ac(b);for(var m=a.m.Ra,k=0;k<b.length;k++){var l=b[k].key;if(Object.prototype.hasOwnProperty.call(m,
|
||||
l)){var p=m[l];if("function"===typeof p){if(l=p(b[k].value))throw Error(l);}else if(!p)throw Error("This template engine does not support the '"+l+"' binding within its templates");}}d="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+a.m.vb(b,{valueAccessors:!0})+" } })()},'"+d.toLowerCase()+"')";return h.createJavaScriptEvaluatorBlock(d)+c}var c=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'|[^>]*))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,
|
||||
d=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{xd:function(b,c,d){c.isTemplateRewritten(b,d)||c.rewriteTemplate(b,function(b){return a.kc.Ld(b,c)},d)},Ld:function(a,f){return a.replace(c,function(a,c,d,e,l){return b(l,c,d,f)}).replace(d,function(a,c){return b(c,"\x3c!-- ko --\x3e","#comment",f)})},md:function(b,c){return a.aa.Xb(function(d,h){var m=d.nextSibling;m&&m.nodeName.toLowerCase()===c&&a.ib(m,b,h)})}}}();a.b("__tr_ambtns",a.kc.md);(function(){a.C={};a.C.F=function(b){if(this.F=b){var c=
|
||||
a.a.R(b);this.ab="script"===c?1:"textarea"===c?2:"template"==c&&b.content&&11===b.content.nodeType?3:4}};a.C.F.prototype.text=function(){var b=1===this.ab?"text":2===this.ab?"value":"innerHTML";if(0==arguments.length)return this.F[b];var c=arguments[0];"innerHTML"===b?a.a.fc(this.F,c):this.F[b]=c};var b=a.a.g.Z()+"_";a.C.F.prototype.data=function(c){if(1===arguments.length)return a.a.g.get(this.F,b+c);a.a.g.set(this.F,b+c,arguments[1])};var c=a.a.g.Z();a.C.F.prototype.nodes=function(){var b=this.F;
|
||||
if(0==arguments.length){var e=a.a.g.get(b,c)||{},f=e.lb||(3===this.ab?b.content:4===this.ab?b:n);if(!f||e.jd){var g=this.text();g&&g!==e.bb&&(f=a.a.Md(g,b.ownerDocument),a.a.g.set(b,c,{lb:f,bb:g,jd:!0}))}return f}e=arguments[0];this.ab!==n&&this.text("");a.a.g.set(b,c,{lb:e})};a.C.ia=function(a){this.F=a};a.C.ia.prototype=new a.C.F;a.C.ia.prototype.constructor=a.C.ia;a.C.ia.prototype.text=function(){if(0==arguments.length){var b=a.a.g.get(this.F,c)||{};b.bb===n&&b.lb&&(b.bb=b.lb.innerHTML);return b.bb}a.a.g.set(this.F,
|
||||
c,{bb:arguments[0]})};a.b("templateSources",a.C);a.b("templateSources.domElement",a.C.F);a.b("templateSources.anonymousTemplate",a.C.ia)})();(function(){function b(b,c,d){var e;for(c=a.h.nextSibling(c);b&&(e=b)!==c;)b=a.h.nextSibling(e),d(e,b)}function c(c,d){if(c.length){var e=c[0],f=c[c.length-1],g=e.parentNode,h=a.ga.instance,m=h.preprocessNode;if(m){b(e,f,function(a,b){var c=a.previousSibling,d=m.call(h,a);d&&(a===e&&(e=d[0]||b),a===f&&(f=d[d.length-1]||c))});c.length=0;if(!e)return;e===f?c.push(e):
|
||||
(c.push(e,f),a.a.Ua(c,g))}b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.vc(d,b)});b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.aa.cd(b,[d])});a.a.Ua(c,g)}}function d(a){return a.nodeType?a:0<a.length?a[0]:null}function e(b,e,f,h,m){m=m||{};var n=(b&&d(b)||f||{}).ownerDocument,B=m.templateEngine||g;a.kc.xd(f,B,n);f=B.renderTemplate(f,h,m,n);if("number"!=typeof f.length||0<f.length&&"number"!=typeof f[0].nodeType)throw Error("Template engine must return an array of DOM nodes");n=!1;switch(e){case "replaceChildren":a.h.va(b,
|
||||
f);n=!0;break;case "replaceNode":a.a.Xc(b,f);n=!0;break;case "ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+e);}n&&(c(f,h),m.afterRender&&a.u.G(m.afterRender,null,[f,h[m.as||"$data"]]),"replaceChildren"==e&&a.i.ma(b,a.i.H));return f}function f(b,c,d){return a.O(b)?b():"function"===typeof b?b(c,d):b}var g;a.gc=function(b){if(b!=n&&!(b instanceof a.ca))throw Error("templateEngine must inherit from ko.templateEngine");g=b};a.dc=function(b,c,h,m,t){h=h||{};if((h.templateEngine||g)==
|
||||
n)throw Error("Set a template engine before calling renderTemplate");t=t||"replaceChildren";if(m){var x=d(m);return a.$(function(){var g=c&&c instanceof a.fa?c:new a.fa(c,null,null,null,{exportDependencies:!0}),n=f(b,g.$data,g),g=e(m,t,n,g,h);"replaceNode"==t&&(m=g,x=d(m))},null,{Sa:function(){return!x||!a.a.Sb(x)},l:x&&"replaceNode"==t?x.parentNode:x})}return a.aa.Xb(function(d){a.dc(b,c,h,d,"replaceNode")})};a.Qd=function(b,d,g,h,m){function x(b,c){a.u.G(a.a.ec,null,[h,b,u,g,r,c]);a.i.ma(h,a.i.H)}
|
||||
function r(a,b){c(b,v);g.afterRender&&g.afterRender(b,a);v=null}function u(a,c){v=m.createChildContext(a,{as:z,noChildContext:g.noChildContext,extend:function(a){a.$index=c;z&&(a[z+"Index"]=c)}});var d=f(b,a,v);return e(h,"ignoreTargetNode",d,v,g)}var v,z=g.as,w=!1===g.includeDestroyed||a.options.foreachHidesDestroyed&&!g.includeDestroyed;if(w||g.beforeRemove||!a.Pc(d))return a.$(function(){var b=a.a.f(d)||[];"undefined"==typeof b.length&&(b=[b]);w&&(b=a.a.jb(b,function(b){return b===n||null===b||
|
||||
!a.a.f(b._destroy)}));x(b)},null,{l:h});x(d.v());var A=d.subscribe(function(a){x(d(),a)},null,"arrayChange");A.l(h);return A};var h=a.a.g.Z(),m=a.a.g.Z();a.c.template={init:function(b,c){var d=a.a.f(c());if("string"==typeof d||"name"in d)a.h.Ea(b);else if("nodes"in d){d=d.nodes||[];if(a.O(d))throw Error('The "nodes" option must be a plain, non-observable array.');var e=d[0]&&d[0].parentNode;e&&a.a.g.get(e,m)||(e=a.a.Yb(d),a.a.g.set(e,m,!0));(new a.C.ia(b)).nodes(e)}else if(d=a.h.childNodes(b),0<d.length)e=
|
||||
a.a.Yb(d),(new a.C.ia(b)).nodes(e);else throw Error("Anonymous template defined, but no template content was provided");return{controlsDescendantBindings:!0}},update:function(b,c,d,e,f){var g=c();c=a.a.f(g);d=!0;e=null;"string"==typeof c?c={}:(g="name"in c?c.name:b,"if"in c&&(d=a.a.f(c["if"])),d&&"ifnot"in c&&(d=!a.a.f(c.ifnot)),d&&!g&&(d=!1));"foreach"in c?e=a.Qd(g,d&&c.foreach||[],c,b,f):d?(d=f,"data"in c&&(d=f.createChildContext(c.data,{as:c.as,noChildContext:c.noChildContext,exportDependencies:!0})),
|
||||
e=a.dc(g,d,c,b)):a.h.Ea(b);f=e;(c=a.a.g.get(b,h))&&"function"==typeof c.s&&c.s();a.a.g.set(b,h,!f||f.ja&&!f.ja()?n:f)}};a.m.Ra.template=function(b){b=a.m.ac(b);return 1==b.length&&b[0].unknown||a.m.Id(b,"name")?null:"This template engine does not support anonymous templates nested within its templates"};a.h.ea.template=!0})();a.b("setTemplateEngine",a.gc);a.b("renderTemplate",a.dc);a.a.Kc=function(a,c,d){if(a.length&&c.length){var e,f,g,h,m;for(e=f=0;(!d||e<d)&&(h=a[f]);++f){for(g=0;m=c[g];++g)if(h.value===
|
||||
m.value){h.moved=m.index;m.moved=h.index;c.splice(g,1);e=g=0;break}e+=g}}};a.a.Pb=function(){function b(b,d,e,f,g){var h=Math.min,m=Math.max,k=[],l,p=b.length,q,n=d.length,r=n-p||1,v=p+n+1,u,w,z;for(l=0;l<=p;l++)for(w=u,k.push(u=[]),z=h(n,l+r),q=m(0,l-1);q<=z;q++)u[q]=q?l?b[l-1]===d[q-1]?w[q-1]:h(w[q]||v,u[q-1]||v)+1:q+1:l+1;h=[];m=[];r=[];l=p;for(q=n;l||q;)n=k[l][q]-1,q&&n===k[l][q-1]?m.push(h[h.length]={status:e,value:d[--q],index:q}):l&&n===k[l-1][q]?r.push(h[h.length]={status:f,value:b[--l],index:l}):
|
||||
(--q,--l,g.sparse||h.push({status:"retained",value:d[q]}));a.a.Kc(r,m,!g.dontLimitMoves&&10*p);return h.reverse()}return function(a,d,e){e="boolean"===typeof e?{dontLimitMoves:e}:e||{};a=a||[];d=d||[];return a.length<d.length?b(a,d,"added","deleted",e):b(d,a,"deleted","added",e)}}();a.b("utils.compareArrays",a.a.Pb);(function(){function b(b,c,d,h,m){var k=[],l=a.$(function(){var l=c(d,m,a.a.Ua(k,b))||[];0<k.length&&(a.a.Xc(k,l),h&&a.u.G(h,null,[d,l,m]));k.length=0;a.a.Nb(k,l)},null,{l:b,Sa:function(){return!a.a.kd(k)}});
|
||||
return{Y:k,$:l.ja()?l:n}}var c=a.a.g.Z(),d=a.a.g.Z();a.a.ec=function(e,f,g,h,m,k){function l(b){y={Aa:b,pb:a.ta(w++)};v.push(y);r||F.push(y)}function p(b){y=t[b];w!==y.pb.v()&&D.push(y);y.pb(w++);a.a.Ua(y.Y,e);v.push(y)}function q(b,c){if(b)for(var d=0,e=c.length;d<e;d++)a.a.D(c[d].Y,function(a){b(a,d,c[d].Aa)})}f=f||[];"undefined"==typeof f.length&&(f=[f]);h=h||{};var t=a.a.g.get(e,c),r=!t,v=[],u=0,w=0,z=[],A=[],C=[],D=[],F=[],y,I=0;if(r)a.a.D(f,l);else{if(!k||t&&t._countWaitingForRemove){var E=
|
||||
a.a.Mb(t,function(a){return a.Aa});k=a.a.Pb(E,f,{dontLimitMoves:h.dontLimitMoves,sparse:!0})}for(var E=0,G,H,K;G=k[E];E++)switch(H=G.moved,K=G.index,G.status){case "deleted":for(;u<K;)p(u++);H===n&&(y=t[u],y.$&&(y.$.s(),y.$=n),a.a.Ua(y.Y,e).length&&(h.beforeRemove&&(v.push(y),I++,y.Aa===d?y=null:C.push(y)),y&&z.push.apply(z,y.Y)));u++;break;case "added":for(;w<K;)p(u++);H!==n?(A.push(v.length),p(H)):l(G.value)}for(;w<f.length;)p(u++);v._countWaitingForRemove=I}a.a.g.set(e,c,v);q(h.beforeMove,D);a.a.D(z,
|
||||
h.beforeRemove?a.oa:a.removeNode);var M,O,P;try{P=e.ownerDocument.activeElement}catch(N){}if(A.length)for(;(E=A.shift())!=n;){y=v[E];for(M=n;E;)if((O=v[--E].Y)&&O.length){M=O[O.length-1];break}for(f=0;u=y.Y[f];M=u,f++)a.h.Wb(e,u,M)}for(E=0;y=v[E];E++){y.Y||a.a.extend(y,b(e,g,y.Aa,m,y.pb));for(f=0;u=y.Y[f];M=u,f++)a.h.Wb(e,u,M);!y.Ed&&m&&(m(y.Aa,y.Y,y.pb),y.Ed=!0,M=y.Y[y.Y.length-1])}P&&e.ownerDocument.activeElement!=P&&P.focus();q(h.beforeRemove,C);for(E=0;E<C.length;++E)C[E].Aa=d;q(h.afterMove,D);
|
||||
q(h.afterAdd,F)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",a.a.ec);a.ba=function(){this.allowTemplateRewriting=!1};a.ba.prototype=new a.ca;a.ba.prototype.constructor=a.ba;a.ba.prototype.renderTemplateSource=function(b,c,d,e){if(c=(9>a.a.W?0:b.nodes)?b.nodes():null)return a.a.la(c.cloneNode(!0).childNodes);b=b.text();return a.a.ua(b,e)};a.ba.Ma=new a.ba;a.gc(a.ba.Ma);a.b("nativeTemplateEngine",a.ba);(function(){a.$a=function(){var a=this.Hd=function(){if(!v||!v.tmpl)return 0;try{if(0<=v.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();
|
||||
this.renderTemplateSource=function(b,e,f,g){g=g||w;f=f||{};if(2>a)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var h=b.data("precompiled");h||(h=b.text()||"",h=v.template(null,"{{ko_with $item.koBindingContext}}"+h+"{{/ko_with}}"),b.data("precompiled",h));b=[e.$data];e=v.extend({koBindingContext:e},f.templateOptions);e=v.tmpl(h,b,e);e.appendTo(g.createElement("div"));v.fragments={};return e};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+
|
||||
a+" })()) }}"};this.addTemplate=function(a,b){w.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(v.tmpl.tag.ko_code={open:"__.push($1 || '');"},v.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};a.$a.prototype=new a.ca;a.$a.prototype.constructor=a.$a;var b=new a.$a;0<b.Hd&&a.gc(b);a.b("jqueryTmplTemplateEngine",a.$a)})()})})();})();
|
||||
@@ -1,15 +1,3 @@
|
||||
ko.bindingHandlers.truncatedText = {
|
||||
update: function(element, valueAccessor, allBindingsAccessor) {
|
||||
var value = ko.utils.unwrapObservable(valueAccessor());
|
||||
if (!value) return
|
||||
var length = ko.utils.unwrapObservable(allBindingsAccessor().length) || ko.bindingHandlers.truncatedText.defaultLength,
|
||||
truncatedValue = value.length > length ? convertHTMLtoText(value.substring(0, Math.min(value.length, length))) + "…" : convertHTMLtoText(value);
|
||||
ko.bindingHandlers.html.update(element, function() {
|
||||
return truncatedValue;
|
||||
});
|
||||
},
|
||||
defaultLength: 15
|
||||
};
|
||||
ko.bindingHandlers.truncatedTextCenter = {
|
||||
update: function(element, valueAccessor, allBindingsAccessor) {
|
||||
var value = ko.utils.unwrapObservable(valueAccessor())
|
||||
@@ -143,17 +131,17 @@ $(document).bind('dragover', function(e) {
|
||||
};
|
||||
})(ko);
|
||||
|
||||
// knockout-sortable 0.11.0 | (c) 2015 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license
|
||||
// knockout-sortable 1.2.0 | (c) 2019 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license
|
||||
;(function(factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// AMD anonymous module
|
||||
define(["knockout", "jquery", "jquery-ui/sortable", "jquery-ui/draggable"], factory);
|
||||
define(["knockout", "jquery", "jquery-ui/ui/widgets/sortable", "jquery-ui/ui/widgets/draggable"], factory);
|
||||
} else if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
|
||||
// CommonJS module
|
||||
var ko = require("knockout"),
|
||||
jQuery = require("jquery");
|
||||
require("jquery-ui/sortable");
|
||||
require("jquery-ui/draggable");
|
||||
require("jquery-ui/ui/widgets/sortable");
|
||||
require("jquery-ui/ui/widgets/draggable");
|
||||
factory(ko, jQuery);
|
||||
} else {
|
||||
// No module loader (plain <script> tag) - put directly in global namespace
|
||||
@@ -185,13 +173,16 @@ $(document).bind('dragover', function(e) {
|
||||
//prepare the proper options for the template binding
|
||||
var prepareTemplateOptions = function(valueAccessor, dataName) {
|
||||
var result = {},
|
||||
options = unwrap(valueAccessor()) || {},
|
||||
options = {},
|
||||
actualAfterRender;
|
||||
|
||||
//build our options to pass to the template engine
|
||||
if (options.data) {
|
||||
if (ko.utils.peekObservable(valueAccessor()).data) {
|
||||
options = unwrap(valueAccessor() || {});
|
||||
result[dataName] = options.data;
|
||||
result.name = options.template;
|
||||
if (options.hasOwnProperty("template")) {
|
||||
result.name = options.template;
|
||||
}
|
||||
} else {
|
||||
result[dataName] = valueAccessor();
|
||||
}
|
||||
@@ -226,7 +217,7 @@ $(document).bind('dragover', function(e) {
|
||||
var unwrapped = unwrap(items);
|
||||
|
||||
if (unwrapped) {
|
||||
for (var i = 0; i < index; i++) {
|
||||
for (var i = 0; i <= index; i++) {
|
||||
//add one for every destroyed item we find before the targetIndex in the target array
|
||||
if (unwrapped[i] && unwrap(unwrapped[i]._destroy)) {
|
||||
index++;
|
||||
@@ -300,15 +291,30 @@ $(document).bind('dragover', function(e) {
|
||||
startActual = sortable.options.start;
|
||||
updateActual = sortable.options.update;
|
||||
|
||||
//ensure draggable table row cells maintain their width while dragging (unless a helper is provided)
|
||||
if ( !sortable.options.helper ) {
|
||||
sortable.options.helper = function(e, ui) {
|
||||
if (ui.is("tr")) {
|
||||
ui.children().each(function() {
|
||||
$(this).width($(this).width());
|
||||
});
|
||||
}
|
||||
return ui;
|
||||
};
|
||||
}
|
||||
|
||||
//initialize sortable binding after template binding has rendered in update function
|
||||
var createTimeout = setTimeout(function() {
|
||||
var dragItem;
|
||||
var originalReceive = sortable.options.receive;
|
||||
|
||||
$element.sortable(ko.utils.extend(sortable.options, {
|
||||
start: function(event, ui) {
|
||||
//track original index
|
||||
var el = ui.item[0];
|
||||
dataSet(el, INDEXKEY, ko.utils.arrayIndexOf(ui.item.parent().children(), el));
|
||||
// Add class to parent for active sorting
|
||||
|
||||
// SABnzbd-edit: Add class to parent for active sorting
|
||||
$(el).parent().parent().addClass('table-active-sorting')
|
||||
|
||||
//make sure that fields have a chance to update model
|
||||
@@ -318,6 +324,11 @@ $(document).bind('dragover', function(e) {
|
||||
}
|
||||
},
|
||||
receive: function(event, ui) {
|
||||
//optionally apply an existing receive handler
|
||||
if (typeof originalReceive === "function") {
|
||||
originalReceive.call(this, event, ui);
|
||||
}
|
||||
|
||||
dragItem = dataGet(ui.item[0], DRAGKEY);
|
||||
if (dragItem) {
|
||||
//copy the model item, if a clone option is provided
|
||||
@@ -337,6 +348,9 @@ $(document).bind('dragover', function(e) {
|
||||
parentEl = ui.item.parent()[0],
|
||||
item = dataGet(el, ITEMKEY) || dragItem;
|
||||
|
||||
if (!item) {
|
||||
$(el).remove();
|
||||
}
|
||||
dragItem = null;
|
||||
|
||||
//make sure that moves only run once, as update fires on multiple containers
|
||||
@@ -385,22 +399,73 @@ $(document).bind('dragover', function(e) {
|
||||
return;
|
||||
}
|
||||
|
||||
//do the actual move
|
||||
if (targetIndex >= 0) {
|
||||
if (sourceParent) {
|
||||
sourceParent.splice(sourceIndex, 1);
|
||||
//if the strategy option is unset or false, employ the order strategy involving removal and insertion of items
|
||||
if (!sortable.hasOwnProperty("strategyMove") || sortable.strategyMove === false) {
|
||||
//do the actual move
|
||||
if (targetIndex >= 0) {
|
||||
if (sourceParent) {
|
||||
sourceParent.splice(sourceIndex, 1);
|
||||
|
||||
//if using deferred updates plugin, force updates
|
||||
if (ko.processAllDeferredBindingUpdates) {
|
||||
ko.processAllDeferredBindingUpdates();
|
||||
//if using deferred updates plugin, force updates
|
||||
if (ko.processAllDeferredBindingUpdates) {
|
||||
ko.processAllDeferredBindingUpdates();
|
||||
}
|
||||
|
||||
//if using deferred updates on knockout 3.4, force updates
|
||||
if (ko.options && ko.options.deferUpdates) {
|
||||
ko.tasks.runEarly();
|
||||
}
|
||||
}
|
||||
|
||||
targetParent.splice(targetIndex, 0, item);
|
||||
}
|
||||
|
||||
targetParent.splice(targetIndex, 0, item);
|
||||
//rendering is handled by manipulating the observableArray; ignore dropped element
|
||||
dataSet(el, ITEMKEY, null);
|
||||
}
|
||||
else { //employ the strategy of moving items
|
||||
if (targetIndex >= 0) {
|
||||
if (sourceParent) {
|
||||
if (sourceParent !== targetParent) {
|
||||
// moving from one list to another
|
||||
|
||||
//rendering is handled by manipulating the observableArray; ignore dropped element
|
||||
dataSet(el, ITEMKEY, null);
|
||||
sourceParent.splice(sourceIndex, 1);
|
||||
targetParent.splice(targetIndex, 0, item);
|
||||
|
||||
//rendering is handled by manipulating the observableArray; ignore dropped element
|
||||
dataSet(el, ITEMKEY, null);
|
||||
ui.item.remove();
|
||||
}
|
||||
else {
|
||||
// moving within same list
|
||||
var underlyingList = unwrap(sourceParent);
|
||||
|
||||
// notify 'beforeChange' subscribers
|
||||
if (sourceParent.valueWillMutate) {
|
||||
sourceParent.valueWillMutate();
|
||||
}
|
||||
|
||||
// move from source index ...
|
||||
underlyingList.splice(sourceIndex, 1);
|
||||
// ... to target index
|
||||
underlyingList.splice(targetIndex, 0, item);
|
||||
|
||||
// notify subscribers
|
||||
if (sourceParent.valueHasMutated) {
|
||||
sourceParent.valueHasMutated();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// drop new element from outside
|
||||
targetParent.splice(targetIndex, 0, item);
|
||||
|
||||
//rendering is handled by manipulating the observableArray; ignore dropped element
|
||||
dataSet(el, ITEMKEY, null);
|
||||
ui.item.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if using deferred updates plugin, force updates
|
||||
if (ko.processAllDeferredBindingUpdates) {
|
||||
@@ -418,6 +483,7 @@ $(document).bind('dragover', function(e) {
|
||||
}
|
||||
},
|
||||
connectWith: sortable.connectClass ? "." + sortable.connectClass : false,
|
||||
// SABnzbd-edit: we need placeholder
|
||||
placeholder: 'sortable-placeholder'
|
||||
}));
|
||||
|
||||
@@ -528,6 +594,7 @@ $(document).bind('dragover', function(e) {
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
ko.bindingHandlers.slider = {
|
||||
init: function(element, valueAccessor, allBindingsAccessor) {
|
||||
var options = allBindingsAccessor().sliderOptions || {};
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
/*!
|
||||
* Knockout JavaScript library v3.4.2
|
||||
* (c) The Knockout.js team - http://knockoutjs.com/
|
||||
* License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
(function() {(function(n){var x=this||(0,eval)("this"),t=x.document,M=x.navigator,u=x.jQuery,H=x.JSON;(function(n){"function"===typeof define&&define.amd?define(["exports","require"],n):"object"===typeof exports&&"object"===typeof module?n(module.exports||exports):n(x.ko={})})(function(N,O){function J(a,c){return null===a||typeof a in R?a===c:!1}function S(b,c){var d;return function(){d||(d=a.a.setTimeout(function(){d=n;b()},c))}}function T(b,c){var d;return function(){clearTimeout(d);d=a.a.setTimeout(b,c)}}function U(a,
|
||||
c){c&&c!==E?"beforeChange"===c?this.Ob(a):this.Ja(a,c):this.Pb(a)}function V(a,c){null!==c&&c.k&&c.k()}function W(a,c){var d=this.Mc,e=d[s];e.T||(this.ob&&this.Oa[c]?(d.Sb(c,a,this.Oa[c]),this.Oa[c]=null,--this.ob):e.s[c]||d.Sb(c,a,e.t?{$:a}:d.yc(a)),a.Ha&&a.Hc())}function K(b,c,d,e){a.d[b]={init:function(b,g,h,l,m){var k,r;a.m(function(){var q=g(),p=a.a.c(q),p=!d!==!p,A=!r;if(A||c||p!==k)A&&a.xa.Ca()&&(r=a.a.wa(a.f.childNodes(b),!0)),p?(A||a.f.fa(b,a.a.wa(r)),a.hb(e?e(m,q):m,b)):a.f.za(b),k=p},null,
|
||||
{i:b});return{controlsDescendantBindings:!0}}};a.h.va[b]=!1;a.f.aa[b]=!0}var a="undefined"!==typeof N?N:{};a.b=function(b,c){for(var d=b.split("."),e=a,f=0;f<d.length-1;f++)e=e[d[f]];e[d[d.length-1]]=c};a.H=function(a,c,d){a[c]=d};a.version="3.4.2";a.b("version",a.version);a.options={deferUpdates:!1,useOnlyNativeEvents:!1};a.a=function(){function b(a,b){for(var c in a)a.hasOwnProperty(c)&&b(c,a[c])}function c(a,b){if(b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}function d(a,b){a.__proto__=
|
||||
b;return a}function e(b,c,d,e){var m=b[c].match(r)||[];a.a.r(d.match(r),function(b){a.a.ra(m,b,e)});b[c]=m.join(" ")}var f={__proto__:[]}instanceof Array,g="function"===typeof Symbol,h={},l={};h[M&&/Firefox\/2/i.test(M.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];h.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");b(h,function(a,b){if(b.length)for(var c=0,d=b.length;c<d;c++)l[b[c]]=a});var m={propertychange:!0},k=
|
||||
t&&function(){for(var a=3,b=t.createElement("div"),c=b.getElementsByTagName("i");b.innerHTML="\x3c!--[if gt IE "+ ++a+"]><i></i><![endif]--\x3e",c[0];);return 4<a?a:n}(),r=/\S+/g;return{gc:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],r:function(a,b){for(var c=0,d=a.length;c<d;c++)b(a[c],c)},o:function(a,b){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b);for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},Vb:function(a,b,c){for(var d=
|
||||
0,e=a.length;d<e;d++)if(b.call(c,a[d],d))return a[d];return null},Na:function(b,c){var d=a.a.o(b,c);0<d?b.splice(d,1):0===d&&b.shift()},Wb:function(b){b=b||[];for(var c=[],d=0,e=b.length;d<e;d++)0>a.a.o(c,b[d])&&c.push(b[d]);return c},ib:function(a,b){a=a||[];for(var c=[],d=0,e=a.length;d<e;d++)c.push(b(a[d],d));return c},Ma:function(a,b){a=a||[];for(var c=[],d=0,e=a.length;d<e;d++)b(a[d],d)&&c.push(a[d]);return c},ta:function(a,b){if(b instanceof Array)a.push.apply(a,b);else for(var c=0,d=b.length;c<
|
||||
d;c++)a.push(b[c]);return a},ra:function(b,c,d){var e=a.a.o(a.a.Bb(b),c);0>e?d&&b.push(c):d||b.splice(e,1)},la:f,extend:c,$a:d,ab:f?d:c,D:b,Ea:function(a,b){if(!a)return a;var c={},d;for(d in a)a.hasOwnProperty(d)&&(c[d]=b(a[d],d,a));return c},rb:function(b){for(;b.firstChild;)a.removeNode(b.firstChild)},nc:function(b){b=a.a.W(b);for(var c=(b[0]&&b[0].ownerDocument||t).createElement("div"),d=0,e=b.length;d<e;d++)c.appendChild(a.ba(b[d]));return c},wa:function(b,c){for(var d=0,e=b.length,m=[];d<e;d++){var k=
|
||||
b[d].cloneNode(!0);m.push(c?a.ba(k):k)}return m},fa:function(b,c){a.a.rb(b);if(c)for(var d=0,e=c.length;d<e;d++)b.appendChild(c[d])},uc:function(b,c){var d=b.nodeType?[b]:b;if(0<d.length){for(var e=d[0],m=e.parentNode,k=0,f=c.length;k<f;k++)m.insertBefore(c[k],e);k=0;for(f=d.length;k<f;k++)a.removeNode(d[k])}},Ba:function(a,b){if(a.length){for(b=8===b.nodeType&&b.parentNode||b;a.length&&a[0].parentNode!==b;)a.splice(0,1);for(;1<a.length&&a[a.length-1].parentNode!==b;)a.length--;if(1<a.length){var c=
|
||||
a[0],d=a[a.length-1];for(a.length=0;c!==d;)a.push(c),c=c.nextSibling;a.push(d)}}return a},wc:function(a,b){7>k?a.setAttribute("selected",b):a.selected=b},cb:function(a){return null===a||a===n?"":a.trim?a.trim():a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},sd:function(a,b){a=a||"";return b.length>a.length?!1:a.substring(0,b.length)===b},Rc:function(a,b){if(a===b)return!0;if(11===a.nodeType)return!1;if(b.contains)return b.contains(3===a.nodeType?a.parentNode:a);if(b.compareDocumentPosition)return 16==
|
||||
(b.compareDocumentPosition(a)&16);for(;a&&a!=b;)a=a.parentNode;return!!a},qb:function(b){return a.a.Rc(b,b.ownerDocument.documentElement)},Tb:function(b){return!!a.a.Vb(b,a.a.qb)},A:function(a){return a&&a.tagName&&a.tagName.toLowerCase()},Zb:function(b){return a.onError?function(){try{return b.apply(this,arguments)}catch(c){throw a.onError&&a.onError(c),c;}}:b},setTimeout:function(b,c){return setTimeout(a.a.Zb(b),c)},dc:function(b){setTimeout(function(){a.onError&&a.onError(b);throw b;},0)},q:function(b,
|
||||
c,d){var e=a.a.Zb(d);d=k&&m[c];if(a.options.useOnlyNativeEvents||d||!u)if(d||"function"!=typeof b.addEventListener)if("undefined"!=typeof b.attachEvent){var f=function(a){e.call(b,a)},l="on"+c;b.attachEvent(l,f);a.a.G.qa(b,function(){b.detachEvent(l,f)})}else throw Error("Browser doesn't support addEventListener or attachEvent");else b.addEventListener(c,e,!1);else u(b).bind(c,e)},Fa:function(b,c){if(!b||!b.nodeType)throw Error("element must be a DOM node when calling triggerEvent");var d;"input"===
|
||||
a.a.A(b)&&b.type&&"click"==c.toLowerCase()?(d=b.type,d="checkbox"==d||"radio"==d):d=!1;if(a.options.useOnlyNativeEvents||!u||d)if("function"==typeof t.createEvent)if("function"==typeof b.dispatchEvent)d=t.createEvent(l[c]||"HTMLEvents"),d.initEvent(c,!0,!0,x,0,0,0,0,0,!1,!1,!1,!1,0,b),b.dispatchEvent(d);else throw Error("The supplied element doesn't support dispatchEvent");else if(d&&b.click)b.click();else if("undefined"!=typeof b.fireEvent)b.fireEvent("on"+c);else throw Error("Browser doesn't support triggering events");
|
||||
else u(b).trigger(c)},c:function(b){return a.I(b)?b():b},Bb:function(b){return a.I(b)?b.p():b},fb:function(b,c,d){var k;c&&("object"===typeof b.classList?(k=b.classList[d?"add":"remove"],a.a.r(c.match(r),function(a){k.call(b.classList,a)})):"string"===typeof b.className.baseVal?e(b.className,"baseVal",c,d):e(b,"className",c,d))},bb:function(b,c){var d=a.a.c(c);if(null===d||d===n)d="";var e=a.f.firstChild(b);!e||3!=e.nodeType||a.f.nextSibling(e)?a.f.fa(b,[b.ownerDocument.createTextNode(d)]):e.data=
|
||||
d;a.a.Wc(b)},vc:function(a,b){a.name=b;if(7>=k)try{a.mergeAttributes(t.createElement("<input name='"+a.name+"'/>"),!1)}catch(c){}},Wc:function(a){9<=k&&(a=1==a.nodeType?a:a.parentNode,a.style&&(a.style.zoom=a.style.zoom))},Sc:function(a){if(k){var b=a.style.width;a.style.width=0;a.style.width=b}},nd:function(b,c){b=a.a.c(b);c=a.a.c(c);for(var d=[],e=b;e<=c;e++)d.push(e);return d},W:function(a){for(var b=[],c=0,d=a.length;c<d;c++)b.push(a[c]);return b},bc:function(a){return g?Symbol(a):a},xd:6===k,
|
||||
yd:7===k,C:k,ic:function(b,c){for(var d=a.a.W(b.getElementsByTagName("input")).concat(a.a.W(b.getElementsByTagName("textarea"))),e="string"==typeof c?function(a){return a.name===c}:function(a){return c.test(a.name)},k=[],m=d.length-1;0<=m;m--)e(d[m])&&k.push(d[m]);return k},kd:function(b){return"string"==typeof b&&(b=a.a.cb(b))?H&&H.parse?H.parse(b):(new Function("return "+b))():null},Gb:function(b,c,d){if(!H||!H.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
|
||||
return H.stringify(a.a.c(b),c,d)},ld:function(c,d,e){e=e||{};var k=e.params||{},m=e.includeFields||this.gc,f=c;if("object"==typeof c&&"form"===a.a.A(c))for(var f=c.action,l=m.length-1;0<=l;l--)for(var g=a.a.ic(c,m[l]),h=g.length-1;0<=h;h--)k[g[h].name]=g[h].value;d=a.a.c(d);var r=t.createElement("form");r.style.display="none";r.action=f;r.method="post";for(var n in d)c=t.createElement("input"),c.type="hidden",c.name=n,c.value=a.a.Gb(a.a.c(d[n])),r.appendChild(c);b(k,function(a,b){var c=t.createElement("input");
|
||||
c.type="hidden";c.name=a;c.value=b;r.appendChild(c)});t.body.appendChild(r);e.submitter?e.submitter(r):r.submit();setTimeout(function(){r.parentNode.removeChild(r)},0)}}}();a.b("utils",a.a);a.b("utils.arrayForEach",a.a.r);a.b("utils.arrayFirst",a.a.Vb);a.b("utils.arrayFilter",a.a.Ma);a.b("utils.arrayGetDistinctValues",a.a.Wb);a.b("utils.arrayIndexOf",a.a.o);a.b("utils.arrayMap",a.a.ib);a.b("utils.arrayPushAll",a.a.ta);a.b("utils.arrayRemoveItem",a.a.Na);a.b("utils.extend",a.a.extend);a.b("utils.fieldsIncludedWithJsonPost",
|
||||
a.a.gc);a.b("utils.getFormFields",a.a.ic);a.b("utils.peekObservable",a.a.Bb);a.b("utils.postJson",a.a.ld);a.b("utils.parseJson",a.a.kd);a.b("utils.registerEventHandler",a.a.q);a.b("utils.stringifyJson",a.a.Gb);a.b("utils.range",a.a.nd);a.b("utils.toggleDomNodeCssClass",a.a.fb);a.b("utils.triggerEvent",a.a.Fa);a.b("utils.unwrapObservable",a.a.c);a.b("utils.objectForEach",a.a.D);a.b("utils.addOrRemoveItem",a.a.ra);a.b("utils.setTextContent",a.a.bb);a.b("unwrap",a.a.c);Function.prototype.bind||(Function.prototype.bind=
|
||||
function(a){var c=this;if(1===arguments.length)return function(){return c.apply(a,arguments)};var d=Array.prototype.slice.call(arguments,1);return function(){var e=d.slice(0);e.push.apply(e,arguments);return c.apply(a,e)}});a.a.e=new function(){function a(b,g){var h=b[d];if(!h||"null"===h||!e[h]){if(!g)return n;h=b[d]="ko"+c++;e[h]={}}return e[h]}var c=0,d="__ko__"+(new Date).getTime(),e={};return{get:function(c,d){var e=a(c,!1);return e===n?n:e[d]},set:function(c,d,e){if(e!==n||a(c,!1)!==n)a(c,!0)[d]=
|
||||
e},clear:function(a){var b=a[d];return b?(delete e[b],a[d]=null,!0):!1},J:function(){return c++ +d}}};a.b("utils.domData",a.a.e);a.b("utils.domData.clear",a.a.e.clear);a.a.G=new function(){function b(b,c){var e=a.a.e.get(b,d);e===n&&c&&(e=[],a.a.e.set(b,d,e));return e}function c(d){var e=b(d,!1);if(e)for(var e=e.slice(0),l=0;l<e.length;l++)e[l](d);a.a.e.clear(d);a.a.G.cleanExternalData(d);if(f[d.nodeType])for(e=d.firstChild;d=e;)e=d.nextSibling,8===d.nodeType&&c(d)}var d=a.a.e.J(),e={1:!0,8:!0,9:!0},
|
||||
f={1:!0,9:!0};return{qa:function(a,c){if("function"!=typeof c)throw Error("Callback must be a function");b(a,!0).push(c)},tc:function(c,e){var f=b(c,!1);f&&(a.a.Na(f,e),0==f.length&&a.a.e.set(c,d,n))},ba:function(b){if(e[b.nodeType]&&(c(b),f[b.nodeType])){var d=[];a.a.ta(d,b.getElementsByTagName("*"));for(var l=0,m=d.length;l<m;l++)c(d[l])}return b},removeNode:function(b){a.ba(b);b.parentNode&&b.parentNode.removeChild(b)},cleanExternalData:function(a){u&&"function"==typeof u.cleanData&&u.cleanData([a])}}};
|
||||
a.ba=a.a.G.ba;a.removeNode=a.a.G.removeNode;a.b("cleanNode",a.ba);a.b("removeNode",a.removeNode);a.b("utils.domNodeDisposal",a.a.G);a.b("utils.domNodeDisposal.addDisposeCallback",a.a.G.qa);a.b("utils.domNodeDisposal.removeDisposeCallback",a.a.G.tc);(function(){var b=[0,"",""],c=[1,"<table>","</table>"],d=[3,"<table><tbody><tr>","</tr></tbody></table>"],e=[1,"<select multiple='multiple'>","</select>"],f={thead:c,tbody:c,tfoot:c,tr:[2,"<table><tbody>","</tbody></table>"],td:d,th:d,option:e,optgroup:e},
|
||||
g=8>=a.a.C;a.a.na=function(c,d){var e;if(u)if(u.parseHTML)e=u.parseHTML(c,d)||[];else{if((e=u.clean([c],d))&&e[0]){for(var k=e[0];k.parentNode&&11!==k.parentNode.nodeType;)k=k.parentNode;k.parentNode&&k.parentNode.removeChild(k)}}else{(e=d)||(e=t);var k=e.parentWindow||e.defaultView||x,r=a.a.cb(c).toLowerCase(),q=e.createElement("div"),p;p=(r=r.match(/^<([a-z]+)[ >]/))&&f[r[1]]||b;r=p[0];p="ignored<div>"+p[1]+c+p[2]+"</div>";"function"==typeof k.innerShiv?q.appendChild(k.innerShiv(p)):(g&&e.appendChild(q),
|
||||
q.innerHTML=p,g&&q.parentNode.removeChild(q));for(;r--;)q=q.lastChild;e=a.a.W(q.lastChild.childNodes)}return e};a.a.Eb=function(b,c){a.a.rb(b);c=a.a.c(c);if(null!==c&&c!==n)if("string"!=typeof c&&(c=c.toString()),u)u(b).html(c);else for(var d=a.a.na(c,b.ownerDocument),e=0;e<d.length;e++)b.appendChild(d[e])}})();a.b("utils.parseHtmlFragment",a.a.na);a.b("utils.setHtml",a.a.Eb);a.N=function(){function b(c,e){if(c)if(8==c.nodeType){var f=a.N.pc(c.nodeValue);null!=f&&e.push({Qc:c,hd:f})}else if(1==c.nodeType)for(var f=
|
||||
0,g=c.childNodes,h=g.length;f<h;f++)b(g[f],e)}var c={};return{yb:function(a){if("function"!=typeof a)throw Error("You can only pass a function to ko.memoization.memoize()");var b=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);c[b]=a;return"\x3c!--[ko_memo:"+b+"]--\x3e"},Bc:function(a,b){var f=c[a];if(f===n)throw Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized.");try{return f.apply(null,b||[]),
|
||||
!0}finally{delete c[a]}},Cc:function(c,e){var f=[];b(c,f);for(var g=0,h=f.length;g<h;g++){var l=f[g].Qc,m=[l];e&&a.a.ta(m,e);a.N.Bc(f[g].hd,m);l.nodeValue="";l.parentNode&&l.parentNode.removeChild(l)}},pc:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:null}}}();a.b("memoization",a.N);a.b("memoization.memoize",a.N.yb);a.b("memoization.unmemoize",a.N.Bc);a.b("memoization.parseMemoText",a.N.pc);a.b("memoization.unmemoizeDomNodeAndDescendants",a.N.Cc);a.Z=function(){function b(){if(e)for(var b=
|
||||
e,c=0,m;g<e;)if(m=d[g++]){if(g>b){if(5E3<=++c){g=e;a.a.dc(Error("'Too much recursion' after processing "+c+" task groups."));break}b=e}try{m()}catch(k){a.a.dc(k)}}}function c(){b();g=e=d.length=0}var d=[],e=0,f=1,g=0;return{scheduler:x.MutationObserver?function(a){var b=t.createElement("div");(new MutationObserver(a)).observe(b,{attributes:!0});return function(){b.classList.toggle("foo")}}(c):t&&"onreadystatechange"in t.createElement("script")?function(a){var b=t.createElement("script");b.onreadystatechange=
|
||||
function(){b.onreadystatechange=null;t.documentElement.removeChild(b);b=null;a()};t.documentElement.appendChild(b)}:function(a){setTimeout(a,0)},Za:function(b){e||a.Z.scheduler(c);d[e++]=b;return f++},cancel:function(a){a-=f-e;a>=g&&a<e&&(d[a]=null)},resetForTesting:function(){var a=e-g;g=e=d.length=0;return a},rd:b}}();a.b("tasks",a.Z);a.b("tasks.schedule",a.Z.Za);a.b("tasks.runEarly",a.Z.rd);a.Aa={throttle:function(b,c){b.throttleEvaluation=c;var d=null;return a.B({read:b,write:function(e){clearTimeout(d);
|
||||
d=a.a.setTimeout(function(){b(e)},c)}})},rateLimit:function(a,c){var d,e,f;"number"==typeof c?d=c:(d=c.timeout,e=c.method);a.gb=!1;f="notifyWhenChangesStop"==e?T:S;a.Wa(function(a){return f(a,d)})},deferred:function(b,c){if(!0!==c)throw Error("The 'deferred' extender only accepts the value 'true', because it is not supported to turn deferral off once enabled.");b.gb||(b.gb=!0,b.Wa(function(c){var e,f=!1;return function(){if(!f){a.Z.cancel(e);e=a.Z.Za(c);try{f=!0,b.notifySubscribers(n,"dirty")}finally{f=
|
||||
!1}}}}))},notify:function(a,c){a.equalityComparer="always"==c?null:J}};var R={undefined:1,"boolean":1,number:1,string:1};a.b("extenders",a.Aa);a.zc=function(b,c,d){this.$=b;this.jb=c;this.Pc=d;this.T=!1;a.H(this,"dispose",this.k)};a.zc.prototype.k=function(){this.T=!0;this.Pc()};a.K=function(){a.a.ab(this,D);D.ub(this)};var E="change",D={ub:function(a){a.F={change:[]};a.Qb=1},Y:function(b,c,d){var e=this;d=d||E;var f=new a.zc(e,c?b.bind(c):b,function(){a.a.Na(e.F[d],f);e.Ka&&e.Ka(d)});e.ua&&e.ua(d);
|
||||
e.F[d]||(e.F[d]=[]);e.F[d].push(f);return f},notifySubscribers:function(b,c){c=c||E;c===E&&this.Kb();if(this.Ra(c)){var d=c===E&&this.Fc||this.F[c].slice(0);try{a.l.Xb();for(var e=0,f;f=d[e];++e)f.T||f.jb(b)}finally{a.l.end()}}},Pa:function(){return this.Qb},Zc:function(a){return this.Pa()!==a},Kb:function(){++this.Qb},Wa:function(b){var c=this,d=a.I(c),e,f,g,h;c.Ja||(c.Ja=c.notifySubscribers,c.notifySubscribers=U);var l=b(function(){c.Ha=!1;d&&h===c&&(h=c.Mb?c.Mb():c());var a=f||c.Ua(g,h);f=e=!1;
|
||||
a&&c.Ja(g=h)});c.Pb=function(a){c.Fc=c.F[E].slice(0);c.Ha=e=!0;h=a;l()};c.Ob=function(a){e||(g=a,c.Ja(a,"beforeChange"))};c.Hc=function(){c.Ua(g,c.p(!0))&&(f=!0)}},Ra:function(a){return this.F[a]&&this.F[a].length},Xc:function(b){if(b)return this.F[b]&&this.F[b].length||0;var c=0;a.a.D(this.F,function(a,b){"dirty"!==a&&(c+=b.length)});return c},Ua:function(a,c){return!this.equalityComparer||!this.equalityComparer(a,c)},extend:function(b){var c=this;b&&a.a.D(b,function(b,e){var f=a.Aa[b];"function"==
|
||||
typeof f&&(c=f(c,e)||c)});return c}};a.H(D,"subscribe",D.Y);a.H(D,"extend",D.extend);a.H(D,"getSubscriptionsCount",D.Xc);a.a.la&&a.a.$a(D,Function.prototype);a.K.fn=D;a.lc=function(a){return null!=a&&"function"==typeof a.Y&&"function"==typeof a.notifySubscribers};a.b("subscribable",a.K);a.b("isSubscribable",a.lc);a.xa=a.l=function(){function b(a){d.push(e);e=a}function c(){e=d.pop()}var d=[],e,f=0;return{Xb:b,end:c,sc:function(b){if(e){if(!a.lc(b))throw Error("Only subscribable things can act as dependencies");
|
||||
e.jb.call(e.Lc,b,b.Gc||(b.Gc=++f))}},w:function(a,d,e){try{return b(),a.apply(d,e||[])}finally{c()}},Ca:function(){if(e)return e.m.Ca()},Va:function(){if(e)return e.Va}}}();a.b("computedContext",a.xa);a.b("computedContext.getDependenciesCount",a.xa.Ca);a.b("computedContext.isInitial",a.xa.Va);a.b("ignoreDependencies",a.wd=a.l.w);var F=a.a.bc("_latestValue");a.O=function(b){function c(){if(0<arguments.length)return c.Ua(c[F],arguments[0])&&(c.ia(),c[F]=arguments[0],c.ha()),this;a.l.sc(c);return c[F]}
|
||||
c[F]=b;a.a.la||a.a.extend(c,a.K.fn);a.K.fn.ub(c);a.a.ab(c,B);a.options.deferUpdates&&a.Aa.deferred(c,!0);return c};var B={equalityComparer:J,p:function(){return this[F]},ha:function(){this.notifySubscribers(this[F])},ia:function(){this.notifySubscribers(this[F],"beforeChange")}};a.a.la&&a.a.$a(B,a.K.fn);var I=a.O.md="__ko_proto__";B[I]=a.O;a.Qa=function(b,c){return null===b||b===n||b[I]===n?!1:b[I]===c?!0:a.Qa(b[I],c)};a.I=function(b){return a.Qa(b,a.O)};a.Da=function(b){return"function"==typeof b&&
|
||||
b[I]===a.O||"function"==typeof b&&b[I]===a.B&&b.$c?!0:!1};a.b("observable",a.O);a.b("isObservable",a.I);a.b("isWriteableObservable",a.Da);a.b("isWritableObservable",a.Da);a.b("observable.fn",B);a.H(B,"peek",B.p);a.H(B,"valueHasMutated",B.ha);a.H(B,"valueWillMutate",B.ia);a.ma=function(b){b=b||[];if("object"!=typeof b||!("length"in b))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");b=a.O(b);a.a.ab(b,a.ma.fn);return b.extend({trackArrayChanges:!0})};
|
||||
a.ma.fn={remove:function(b){for(var c=this.p(),d=[],e="function"!=typeof b||a.I(b)?function(a){return a===b}:b,f=0;f<c.length;f++){var g=c[f];e(g)&&(0===d.length&&this.ia(),d.push(g),c.splice(f,1),f--)}d.length&&this.ha();return d},removeAll:function(b){if(b===n){var c=this.p(),d=c.slice(0);this.ia();c.splice(0,c.length);this.ha();return d}return b?this.remove(function(c){return 0<=a.a.o(b,c)}):[]},destroy:function(b){var c=this.p(),d="function"!=typeof b||a.I(b)?function(a){return a===b}:b;this.ia();
|
||||
for(var e=c.length-1;0<=e;e--)d(c[e])&&(c[e]._destroy=!0);this.ha()},destroyAll:function(b){return b===n?this.destroy(function(){return!0}):b?this.destroy(function(c){return 0<=a.a.o(b,c)}):[]},indexOf:function(b){var c=this();return a.a.o(c,b)},replace:function(a,c){var d=this.indexOf(a);0<=d&&(this.ia(),this.p()[d]=c,this.ha())}};a.a.la&&a.a.$a(a.ma.fn,a.O.fn);a.a.r("pop push reverse shift sort splice unshift".split(" "),function(b){a.ma.fn[b]=function(){var a=this.p();this.ia();this.Yb(a,b,arguments);
|
||||
var d=a[b].apply(a,arguments);this.ha();return d===a?this:d}});a.a.r(["slice"],function(b){a.ma.fn[b]=function(){var a=this();return a[b].apply(a,arguments)}});a.b("observableArray",a.ma);a.Aa.trackArrayChanges=function(b,c){function d(){if(!e){e=!0;l=b.notifySubscribers;b.notifySubscribers=function(a,b){b&&b!==E||++h;return l.apply(this,arguments)};var c=[].concat(b.p()||[]);f=null;g=b.Y(function(d){d=[].concat(d||[]);if(b.Ra("arrayChange")){var e;if(!f||1<h)f=a.a.lb(c,d,b.kb);e=f}c=d;f=null;h=0;
|
||||
e&&e.length&&b.notifySubscribers(e,"arrayChange")})}}b.kb={};c&&"object"==typeof c&&a.a.extend(b.kb,c);b.kb.sparse=!0;if(!b.Yb){var e=!1,f=null,g,h=0,l,m=b.ua,k=b.Ka;b.ua=function(a){m&&m.call(b,a);"arrayChange"===a&&d()};b.Ka=function(a){k&&k.call(b,a);"arrayChange"!==a||b.Ra("arrayChange")||(l&&(b.notifySubscribers=l,l=n),g.k(),e=!1)};b.Yb=function(b,c,d){function k(a,b,c){return m[m.length]={status:a,value:b,index:c}}if(e&&!h){var m=[],l=b.length,g=d.length,G=0;switch(c){case "push":G=l;case "unshift":for(c=
|
||||
0;c<g;c++)k("added",d[c],G+c);break;case "pop":G=l-1;case "shift":l&&k("deleted",b[G],G);break;case "splice":c=Math.min(Math.max(0,0>d[0]?l+d[0]:d[0]),l);for(var l=1===g?l:Math.min(c+(d[1]||0),l),g=c+g-2,G=Math.max(l,g),n=[],s=[],w=2;c<G;++c,++w)c<l&&s.push(k("deleted",b[c],c)),c<g&&n.push(k("added",d[w],c));a.a.hc(s,n);break;default:return}f=m}}}};var s=a.a.bc("_state");a.m=a.B=function(b,c,d){function e(){if(0<arguments.length){if("function"===typeof f)f.apply(g.sb,arguments);else throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
|
||||
return this}a.l.sc(e);(g.V||g.t&&e.Sa())&&e.U();return g.M}"object"===typeof b?d=b:(d=d||{},b&&(d.read=b));if("function"!=typeof d.read)throw Error("Pass a function that returns the value of the ko.computed");var f=d.write,g={M:n,da:!0,V:!0,Ta:!1,Hb:!1,T:!1,Ya:!1,t:!1,od:d.read,sb:c||d.owner,i:d.disposeWhenNodeIsRemoved||d.i||null,ya:d.disposeWhen||d.ya,pb:null,s:{},L:0,fc:null};e[s]=g;e.$c="function"===typeof f;a.a.la||a.a.extend(e,a.K.fn);a.K.fn.ub(e);a.a.ab(e,z);d.pure?(g.Ya=!0,g.t=!0,a.a.extend(e,
|
||||
Y)):d.deferEvaluation&&a.a.extend(e,Z);a.options.deferUpdates&&a.Aa.deferred(e,!0);g.i&&(g.Hb=!0,g.i.nodeType||(g.i=null));g.t||d.deferEvaluation||e.U();g.i&&e.ca()&&a.a.G.qa(g.i,g.pb=function(){e.k()});return e};var z={equalityComparer:J,Ca:function(){return this[s].L},Sb:function(a,c,d){if(this[s].Ya&&c===this)throw Error("A 'pure' computed must not be called recursively");this[s].s[a]=d;d.Ia=this[s].L++;d.pa=c.Pa()},Sa:function(){var a,c,d=this[s].s;for(a in d)if(d.hasOwnProperty(a)&&(c=d[a],this.oa&&
|
||||
c.$.Ha||c.$.Zc(c.pa)))return!0},gd:function(){this.oa&&!this[s].Ta&&this.oa(!1)},ca:function(){var a=this[s];return a.V||0<a.L},qd:function(){this.Ha?this[s].V&&(this[s].da=!0):this.ec()},yc:function(a){if(a.gb&&!this[s].i){var c=a.Y(this.gd,this,"dirty"),d=a.Y(this.qd,this);return{$:a,k:function(){c.k();d.k()}}}return a.Y(this.ec,this)},ec:function(){var b=this,c=b.throttleEvaluation;c&&0<=c?(clearTimeout(this[s].fc),this[s].fc=a.a.setTimeout(function(){b.U(!0)},c)):b.oa?b.oa(!0):b.U(!0)},U:function(b){var c=
|
||||
this[s],d=c.ya,e=!1;if(!c.Ta&&!c.T){if(c.i&&!a.a.qb(c.i)||d&&d()){if(!c.Hb){this.k();return}}else c.Hb=!1;c.Ta=!0;try{e=this.Vc(b)}finally{c.Ta=!1}c.L||this.k();return e}},Vc:function(b){var c=this[s],d=!1,e=c.Ya?n:!c.L,f={Mc:this,Oa:c.s,ob:c.L};a.l.Xb({Lc:f,jb:W,m:this,Va:e});c.s={};c.L=0;f=this.Uc(c,f);this.Ua(c.M,f)&&(c.t||this.notifySubscribers(c.M,"beforeChange"),c.M=f,c.t?this.Kb():b&&this.notifySubscribers(c.M),d=!0);e&&this.notifySubscribers(c.M,"awake");return d},Uc:function(b,c){try{var d=
|
||||
b.od;return b.sb?d.call(b.sb):d()}finally{a.l.end(),c.ob&&!b.t&&a.a.D(c.Oa,V),b.da=b.V=!1}},p:function(a){var c=this[s];(c.V&&(a||!c.L)||c.t&&this.Sa())&&this.U();return c.M},Wa:function(b){a.K.fn.Wa.call(this,b);this.Mb=function(){this[s].da?this.U():this[s].V=!1;return this[s].M};this.oa=function(a){this.Ob(this[s].M);this[s].V=!0;a&&(this[s].da=!0);this.Pb(this)}},k:function(){var b=this[s];!b.t&&b.s&&a.a.D(b.s,function(a,b){b.k&&b.k()});b.i&&b.pb&&a.a.G.tc(b.i,b.pb);b.s=null;b.L=0;b.T=!0;b.da=
|
||||
!1;b.V=!1;b.t=!1;b.i=null}},Y={ua:function(b){var c=this,d=c[s];if(!d.T&&d.t&&"change"==b){d.t=!1;if(d.da||c.Sa())d.s=null,d.L=0,c.U()&&c.Kb();else{var e=[];a.a.D(d.s,function(a,b){e[b.Ia]=a});a.a.r(e,function(a,b){var e=d.s[a],l=c.yc(e.$);l.Ia=b;l.pa=e.pa;d.s[a]=l})}d.T||c.notifySubscribers(d.M,"awake")}},Ka:function(b){var c=this[s];c.T||"change"!=b||this.Ra("change")||(a.a.D(c.s,function(a,b){b.k&&(c.s[a]={$:b.$,Ia:b.Ia,pa:b.pa},b.k())}),c.t=!0,this.notifySubscribers(n,"asleep"))},Pa:function(){var b=
|
||||
this[s];b.t&&(b.da||this.Sa())&&this.U();return a.K.fn.Pa.call(this)}},Z={ua:function(a){"change"!=a&&"beforeChange"!=a||this.p()}};a.a.la&&a.a.$a(z,a.K.fn);var P=a.O.md;a.m[P]=a.O;z[P]=a.m;a.bd=function(b){return a.Qa(b,a.m)};a.cd=function(b){return a.Qa(b,a.m)&&b[s]&&b[s].Ya};a.b("computed",a.m);a.b("dependentObservable",a.m);a.b("isComputed",a.bd);a.b("isPureComputed",a.cd);a.b("computed.fn",z);a.H(z,"peek",z.p);a.H(z,"dispose",z.k);a.H(z,"isActive",z.ca);a.H(z,"getDependenciesCount",z.Ca);a.rc=
|
||||
function(b,c){if("function"===typeof b)return a.m(b,c,{pure:!0});b=a.a.extend({},b);b.pure=!0;return a.m(b,c)};a.b("pureComputed",a.rc);(function(){function b(a,f,g){g=g||new d;a=f(a);if("object"!=typeof a||null===a||a===n||a instanceof RegExp||a instanceof Date||a instanceof String||a instanceof Number||a instanceof Boolean)return a;var h=a instanceof Array?[]:{};g.save(a,h);c(a,function(c){var d=f(a[c]);switch(typeof d){case "boolean":case "number":case "string":case "function":h[c]=d;break;case "object":case "undefined":var k=
|
||||
g.get(d);h[c]=k!==n?k:b(d,f,g)}});return h}function c(a,b){if(a instanceof Array){for(var c=0;c<a.length;c++)b(c);"function"==typeof a.toJSON&&b("toJSON")}else for(c in a)b(c)}function d(){this.keys=[];this.Lb=[]}a.Ac=function(c){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");return b(c,function(b){for(var c=0;a.I(b)&&10>c;c++)b=b();return b})};a.toJSON=function(b,c,d){b=a.Ac(b);return a.a.Gb(b,c,d)};d.prototype={save:function(b,c){var d=a.a.o(this.keys,
|
||||
b);0<=d?this.Lb[d]=c:(this.keys.push(b),this.Lb.push(c))},get:function(b){b=a.a.o(this.keys,b);return 0<=b?this.Lb[b]:n}}})();a.b("toJS",a.Ac);a.b("toJSON",a.toJSON);(function(){a.j={u:function(b){switch(a.a.A(b)){case "option":return!0===b.__ko__hasDomDataOptionValue__?a.a.e.get(b,a.d.options.zb):7>=a.a.C?b.getAttributeNode("value")&&b.getAttributeNode("value").specified?b.value:b.text:b.value;case "select":return 0<=b.selectedIndex?a.j.u(b.options[b.selectedIndex]):n;default:return b.value}},ja:function(b,
|
||||
c,d){switch(a.a.A(b)){case "option":switch(typeof c){case "string":a.a.e.set(b,a.d.options.zb,n);"__ko__hasDomDataOptionValue__"in b&&delete b.__ko__hasDomDataOptionValue__;b.value=c;break;default:a.a.e.set(b,a.d.options.zb,c),b.__ko__hasDomDataOptionValue__=!0,b.value="number"===typeof c?c:""}break;case "select":if(""===c||null===c)c=n;for(var e=-1,f=0,g=b.options.length,h;f<g;++f)if(h=a.j.u(b.options[f]),h==c||""==h&&c===n){e=f;break}if(d||0<=e||c===n&&1<b.size)b.selectedIndex=e;break;default:if(null===
|
||||
c||c===n)c="";b.value=c}}}})();a.b("selectExtensions",a.j);a.b("selectExtensions.readValue",a.j.u);a.b("selectExtensions.writeValue",a.j.ja);a.h=function(){function b(b){b=a.a.cb(b);123===b.charCodeAt(0)&&(b=b.slice(1,-1));var c=[],d=b.match(e),r,h=[],p=0;if(d){d.push(",");for(var A=0,y;y=d[A];++A){var v=y.charCodeAt(0);if(44===v){if(0>=p){c.push(r&&h.length?{key:r,value:h.join("")}:{unknown:r||h.join("")});r=p=0;h=[];continue}}else if(58===v){if(!p&&!r&&1===h.length){r=h.pop();continue}}else 47===
|
||||
v&&A&&1<y.length?(v=d[A-1].match(f))&&!g[v[0]]&&(b=b.substr(b.indexOf(y)+1),d=b.match(e),d.push(","),A=-1,y="/"):40===v||123===v||91===v?++p:41===v||125===v||93===v?--p:r||h.length||34!==v&&39!==v||(y=y.slice(1,-1));h.push(y)}}return c}var c=["true","false","null","undefined"],d=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i,e=RegExp("\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|/(?:[^/\\\\]|\\\\.)*/w*|[^\\s:,/][^,\"'{}()/:[\\]]*[^\\s,\"'{}()/:[\\]]|[^\\s]","g"),f=/[\])"'A-Za-z0-9_$]+$/,
|
||||
g={"in":1,"return":1,"typeof":1},h={};return{va:[],ga:h,Ab:b,Xa:function(e,m){function k(b,e){var m;if(!A){var l=a.getBindingHandler(b);if(l&&l.preprocess&&!(e=l.preprocess(e,b,k)))return;if(l=h[b])m=e,0<=a.a.o(c,m)?m=!1:(l=m.match(d),m=null===l?!1:l[1]?"Object("+l[1]+")"+l[2]:m),l=m;l&&g.push("'"+b+"':function(_z){"+m+"=_z}")}p&&(e="function(){return "+e+" }");f.push("'"+b+"':"+e)}m=m||{};var f=[],g=[],p=m.valueAccessors,A=m.bindingParams,y="string"===typeof e?b(e):e;a.a.r(y,function(a){k(a.key||
|
||||
a.unknown,a.value)});g.length&&k("_ko_property_writers","{"+g.join(",")+" }");return f.join(",")},fd:function(a,b){for(var c=0;c<a.length;c++)if(a[c].key==b)return!0;return!1},Ga:function(b,c,d,e,f){if(b&&a.I(b))!a.Da(b)||f&&b.p()===e||b(e);else if((b=c.get("_ko_property_writers"))&&b[d])b[d](e)}}}();a.b("expressionRewriting",a.h);a.b("expressionRewriting.bindingRewriteValidators",a.h.va);a.b("expressionRewriting.parseObjectLiteral",a.h.Ab);a.b("expressionRewriting.preProcessBindings",a.h.Xa);a.b("expressionRewriting._twoWayBindings",
|
||||
a.h.ga);a.b("jsonExpressionRewriting",a.h);a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",a.h.Xa);(function(){function b(a){return 8==a.nodeType&&g.test(f?a.text:a.nodeValue)}function c(a){return 8==a.nodeType&&h.test(f?a.text:a.nodeValue)}function d(a,d){for(var e=a,f=1,l=[];e=e.nextSibling;){if(c(e)&&(f--,0===f))return l;l.push(e);b(e)&&f++}if(!d)throw Error("Cannot find closing comment tag to match: "+a.nodeValue);return null}function e(a,b){var c=d(a,b);return c?0<c.length?c[c.length-
|
||||
1].nextSibling:a.nextSibling:null}var f=t&&"\x3c!--test--\x3e"===t.createComment("test").text,g=f?/^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/:/^\s*ko(?:\s+([\s\S]+))?\s*$/,h=f?/^\x3c!--\s*\/ko\s*--\x3e$/:/^\s*\/ko\s*$/,l={ul:!0,ol:!0};a.f={aa:{},childNodes:function(a){return b(a)?d(a):a.childNodes},za:function(c){if(b(c)){c=a.f.childNodes(c);for(var d=0,e=c.length;d<e;d++)a.removeNode(c[d])}else a.a.rb(c)},fa:function(c,d){if(b(c)){a.f.za(c);for(var e=c.nextSibling,f=0,l=d.length;f<l;f++)e.parentNode.insertBefore(d[f],
|
||||
e)}else a.a.fa(c,d)},qc:function(a,c){b(a)?a.parentNode.insertBefore(c,a.nextSibling):a.firstChild?a.insertBefore(c,a.firstChild):a.appendChild(c)},kc:function(c,d,e){e?b(c)?c.parentNode.insertBefore(d,e.nextSibling):e.nextSibling?c.insertBefore(d,e.nextSibling):c.appendChild(d):a.f.qc(c,d)},firstChild:function(a){return b(a)?!a.nextSibling||c(a.nextSibling)?null:a.nextSibling:a.firstChild},nextSibling:function(a){b(a)&&(a=e(a));return a.nextSibling&&c(a.nextSibling)?null:a.nextSibling},Yc:b,vd:function(a){return(a=
|
||||
(f?a.text:a.nodeValue).match(g))?a[1]:null},oc:function(d){if(l[a.a.A(d)]){var k=d.firstChild;if(k){do if(1===k.nodeType){var f;f=k.firstChild;var g=null;if(f){do if(g)g.push(f);else if(b(f)){var h=e(f,!0);h?f=h:g=[f]}else c(f)&&(g=[f]);while(f=f.nextSibling)}if(f=g)for(g=k.nextSibling,h=0;h<f.length;h++)g?d.insertBefore(f[h],g):d.appendChild(f[h])}while(k=k.nextSibling)}}}}})();a.b("virtualElements",a.f);a.b("virtualElements.allowedBindings",a.f.aa);a.b("virtualElements.emptyNode",a.f.za);a.b("virtualElements.insertAfter",
|
||||
a.f.kc);a.b("virtualElements.prepend",a.f.qc);a.b("virtualElements.setDomNodeChildren",a.f.fa);(function(){a.S=function(){this.Kc={}};a.a.extend(a.S.prototype,{nodeHasBindings:function(b){switch(b.nodeType){case 1:return null!=b.getAttribute("data-bind")||a.g.getComponentNameForNode(b);case 8:return a.f.Yc(b);default:return!1}},getBindings:function(b,c){var d=this.getBindingsString(b,c),d=d?this.parseBindingsString(d,c,b):null;return a.g.Rb(d,b,c,!1)},getBindingAccessors:function(b,c){var d=this.getBindingsString(b,
|
||||
c),d=d?this.parseBindingsString(d,c,b,{valueAccessors:!0}):null;return a.g.Rb(d,b,c,!0)},getBindingsString:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind");case 8:return a.f.vd(b);default:return null}},parseBindingsString:function(b,c,d,e){try{var f=this.Kc,g=b+(e&&e.valueAccessors||""),h;if(!(h=f[g])){var l,m="with($context){with($data||{}){return{"+a.h.Xa(b,e)+"}}}";l=new Function("$context","$element",m);h=f[g]=l}return h(c,d)}catch(k){throw k.message="Unable to parse bindings.\nBindings value: "+
|
||||
b+"\nMessage: "+k.message,k;}}});a.S.instance=new a.S})();a.b("bindingProvider",a.S);(function(){function b(a){return function(){return a}}function c(a){return a()}function d(b){return a.a.Ea(a.l.w(b),function(a,c){return function(){return b()[c]}})}function e(c,e,k){return"function"===typeof c?d(c.bind(null,e,k)):a.a.Ea(c,b)}function f(a,b){return d(this.getBindings.bind(this,a,b))}function g(b,c,d){var e,k=a.f.firstChild(c),f=a.S.instance,m=f.preprocessNode;if(m){for(;e=k;)k=a.f.nextSibling(e),
|
||||
m.call(f,e);k=a.f.firstChild(c)}for(;e=k;)k=a.f.nextSibling(e),h(b,e,d)}function h(b,c,d){var e=!0,k=1===c.nodeType;k&&a.f.oc(c);if(k&&d||a.S.instance.nodeHasBindings(c))e=m(c,null,b,d).shouldBindDescendants;e&&!r[a.a.A(c)]&&g(b,c,!k)}function l(b){var c=[],d={},e=[];a.a.D(b,function X(k){if(!d[k]){var f=a.getBindingHandler(k);f&&(f.after&&(e.push(k),a.a.r(f.after,function(c){if(b[c]){if(-1!==a.a.o(e,c))throw Error("Cannot combine the following bindings, because they have a cyclic dependency: "+e.join(", "));
|
||||
X(c)}}),e.length--),c.push({key:k,jc:f}));d[k]=!0}});return c}function m(b,d,e,k){var m=a.a.e.get(b,q);if(!d){if(m)throw Error("You cannot apply bindings multiple times to the same element.");a.a.e.set(b,q,!0)}!m&&k&&a.xc(b,e);var g;if(d&&"function"!==typeof d)g=d;else{var h=a.S.instance,r=h.getBindingAccessors||f,p=a.B(function(){(g=d?d(e,b):r.call(h,b,e))&&e.Q&&e.Q();return g},null,{i:b});g&&p.ca()||(p=null)}var s;if(g){var t=p?function(a){return function(){return c(p()[a])}}:function(a){return g[a]},
|
||||
u=function(){return a.a.Ea(p?p():g,c)};u.get=function(a){return g[a]&&c(t(a))};u.has=function(a){return a in g};k=l(g);a.a.r(k,function(c){var d=c.jc.init,k=c.jc.update,f=c.key;if(8===b.nodeType&&!a.f.aa[f])throw Error("The binding '"+f+"' cannot be used with virtual elements");try{"function"==typeof d&&a.l.w(function(){var a=d(b,t(f),u,e.$data,e);if(a&&a.controlsDescendantBindings){if(s!==n)throw Error("Multiple bindings ("+s+" and "+f+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");
|
||||
s=f}}),"function"==typeof k&&a.B(function(){k(b,t(f),u,e.$data,e)},null,{i:b})}catch(m){throw m.message='Unable to process binding "'+f+": "+g[f]+'"\nMessage: '+m.message,m;}})}return{shouldBindDescendants:s===n}}function k(b){return b&&b instanceof a.R?b:new a.R(b)}a.d={};var r={script:!0,textarea:!0,template:!0};a.getBindingHandler=function(b){return a.d[b]};a.R=function(b,c,d,e,k){function f(){var k=g?b():b,m=a.a.c(k);c?(c.Q&&c.Q(),a.a.extend(l,c),l.Q=r):(l.$parents=[],l.$root=m,l.ko=a);l.$rawData=
|
||||
k;l.$data=m;d&&(l[d]=m);e&&e(l,c,m);return l.$data}function m(){return h&&!a.a.Tb(h)}var l=this,g="function"==typeof b&&!a.I(b),h,r;k&&k.exportDependencies?f():(r=a.B(f,null,{ya:m,i:!0}),r.ca()&&(l.Q=r,r.equalityComparer=null,h=[],r.Dc=function(b){h.push(b);a.a.G.qa(b,function(b){a.a.Na(h,b);h.length||(r.k(),l.Q=r=n)})}))};a.R.prototype.createChildContext=function(b,c,d,e){return new a.R(b,this,c,function(a,b){a.$parentContext=b;a.$parent=b.$data;a.$parents=(b.$parents||[]).slice(0);a.$parents.unshift(a.$parent);
|
||||
d&&d(a)},e)};a.R.prototype.extend=function(b){return new a.R(this.Q||this.$data,this,null,function(c,d){c.$rawData=d.$rawData;a.a.extend(c,"function"==typeof b?b():b)})};a.R.prototype.ac=function(a,b){return this.createChildContext(a,b,null,{exportDependencies:!0})};var q=a.a.e.J(),p=a.a.e.J();a.xc=function(b,c){if(2==arguments.length)a.a.e.set(b,p,c),c.Q&&c.Q.Dc(b);else return a.a.e.get(b,p)};a.La=function(b,c,d){1===b.nodeType&&a.f.oc(b);return m(b,c,k(d),!0)};a.Ic=function(b,c,d){d=k(d);return a.La(b,
|
||||
e(c,d,b),d)};a.hb=function(a,b){1!==b.nodeType&&8!==b.nodeType||g(k(a),b,!0)};a.Ub=function(a,b){!u&&x.jQuery&&(u=x.jQuery);if(b&&1!==b.nodeType&&8!==b.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");b=b||x.document.body;h(k(a),b,!0)};a.nb=function(b){switch(b.nodeType){case 1:case 8:var c=a.xc(b);if(c)return c;if(b.parentNode)return a.nb(b.parentNode)}return n};a.Oc=function(b){return(b=a.nb(b))?b.$data:n};a.b("bindingHandlers",
|
||||
a.d);a.b("applyBindings",a.Ub);a.b("applyBindingsToDescendants",a.hb);a.b("applyBindingAccessorsToNode",a.La);a.b("applyBindingsToNode",a.Ic);a.b("contextFor",a.nb);a.b("dataFor",a.Oc)})();(function(b){function c(c,e){var m=f.hasOwnProperty(c)?f[c]:b,k;m?m.Y(e):(m=f[c]=new a.K,m.Y(e),d(c,function(b,d){var e=!(!d||!d.synchronous);g[c]={definition:b,dd:e};delete f[c];k||e?m.notifySubscribers(b):a.Z.Za(function(){m.notifySubscribers(b)})}),k=!0)}function d(a,b){e("getConfig",[a],function(c){c?e("loadComponent",
|
||||
[a,c],function(a){b(a,c)}):b(null,null)})}function e(c,d,f,k){k||(k=a.g.loaders.slice(0));var g=k.shift();if(g){var q=g[c];if(q){var p=!1;if(q.apply(g,d.concat(function(a){p?f(null):null!==a?f(a):e(c,d,f,k)}))!==b&&(p=!0,!g.suppressLoaderExceptions))throw Error("Component loaders must supply values by invoking the callback, not by returning values synchronously.");}else e(c,d,f,k)}else f(null)}var f={},g={};a.g={get:function(d,e){var f=g.hasOwnProperty(d)?g[d]:b;f?f.dd?a.l.w(function(){e(f.definition)}):
|
||||
a.Z.Za(function(){e(f.definition)}):c(d,e)},$b:function(a){delete g[a]},Nb:e};a.g.loaders=[];a.b("components",a.g);a.b("components.get",a.g.get);a.b("components.clearCachedDefinition",a.g.$b)})();(function(){function b(b,c,d,e){function g(){0===--y&&e(h)}var h={},y=2,v=d.template;d=d.viewModel;v?f(c,v,function(c){a.g.Nb("loadTemplate",[b,c],function(a){h.template=a;g()})}):g();d?f(c,d,function(c){a.g.Nb("loadViewModel",[b,c],function(a){h[l]=a;g()})}):g()}function c(a,b,d){if("function"===typeof b)d(function(a){return new b(a)});
|
||||
else if("function"===typeof b[l])d(b[l]);else if("instance"in b){var e=b.instance;d(function(){return e})}else"viewModel"in b?c(a,b.viewModel,d):a("Unknown viewModel value: "+b)}function d(b){switch(a.a.A(b)){case "script":return a.a.na(b.text);case "textarea":return a.a.na(b.value);case "template":if(e(b.content))return a.a.wa(b.content.childNodes)}return a.a.wa(b.childNodes)}function e(a){return x.DocumentFragment?a instanceof DocumentFragment:a&&11===a.nodeType}function f(a,b,c){"string"===typeof b.require?
|
||||
O||x.require?(O||x.require)([b.require],c):a("Uses require, but no AMD loader is present"):c(b)}function g(a){return function(b){throw Error("Component '"+a+"': "+b);}}var h={};a.g.register=function(b,c){if(!c)throw Error("Invalid configuration for "+b);if(a.g.wb(b))throw Error("Component "+b+" is already registered");h[b]=c};a.g.wb=function(a){return h.hasOwnProperty(a)};a.g.ud=function(b){delete h[b];a.g.$b(b)};a.g.cc={getConfig:function(a,b){b(h.hasOwnProperty(a)?h[a]:null)},loadComponent:function(a,
|
||||
c,d){var e=g(a);f(e,c,function(c){b(a,e,c,d)})},loadTemplate:function(b,c,f){b=g(b);if("string"===typeof c)f(a.a.na(c));else if(c instanceof Array)f(c);else if(e(c))f(a.a.W(c.childNodes));else if(c.element)if(c=c.element,x.HTMLElement?c instanceof HTMLElement:c&&c.tagName&&1===c.nodeType)f(d(c));else if("string"===typeof c){var l=t.getElementById(c);l?f(d(l)):b("Cannot find element with ID "+c)}else b("Unknown element type: "+c);else b("Unknown template value: "+c)},loadViewModel:function(a,b,d){c(g(a),
|
||||
b,d)}};var l="createViewModel";a.b("components.register",a.g.register);a.b("components.isRegistered",a.g.wb);a.b("components.unregister",a.g.ud);a.b("components.defaultLoader",a.g.cc);a.g.loaders.push(a.g.cc);a.g.Ec=h})();(function(){function b(b,e){var f=b.getAttribute("params");if(f){var f=c.parseBindingsString(f,e,b,{valueAccessors:!0,bindingParams:!0}),f=a.a.Ea(f,function(c){return a.m(c,null,{i:b})}),g=a.a.Ea(f,function(c){var e=c.p();return c.ca()?a.m({read:function(){return a.a.c(c())},write:a.Da(e)&&
|
||||
function(a){c()(a)},i:b}):e});g.hasOwnProperty("$raw")||(g.$raw=f);return g}return{$raw:{}}}a.g.getComponentNameForNode=function(b){var c=a.a.A(b);if(a.g.wb(c)&&(-1!=c.indexOf("-")||"[object HTMLUnknownElement]"==""+b||8>=a.a.C&&b.tagName===c))return c};a.g.Rb=function(c,e,f,g){if(1===e.nodeType){var h=a.g.getComponentNameForNode(e);if(h){c=c||{};if(c.component)throw Error('Cannot use the "component" binding on a custom element matching a component');var l={name:h,params:b(e,f)};c.component=g?function(){return l}:
|
||||
l}}return c};var c=new a.S;9>a.a.C&&(a.g.register=function(a){return function(b){t.createElement(b);return a.apply(this,arguments)}}(a.g.register),t.createDocumentFragment=function(b){return function(){var c=b(),f=a.g.Ec,g;for(g in f)f.hasOwnProperty(g)&&c.createElement(g);return c}}(t.createDocumentFragment))})();(function(b){function c(b,c,d){c=c.template;if(!c)throw Error("Component '"+b+"' has no template");b=a.a.wa(c);a.f.fa(d,b)}function d(a,b,c,d){var e=a.createViewModel;return e?e.call(a,
|
||||
d,{element:b,templateNodes:c}):d}var e=0;a.d.component={init:function(f,g,h,l,m){function k(){var a=r&&r.dispose;"function"===typeof a&&a.call(r);q=r=null}var r,q,p=a.a.W(a.f.childNodes(f));a.a.G.qa(f,k);a.m(function(){var l=a.a.c(g()),h,v;"string"===typeof l?h=l:(h=a.a.c(l.name),v=a.a.c(l.params));if(!h)throw Error("No component name specified");var n=q=++e;a.g.get(h,function(e){if(q===n){k();if(!e)throw Error("Unknown component '"+h+"'");c(h,e,f);var l=d(e,f,p,v);e=m.createChildContext(l,b,function(a){a.$component=
|
||||
l;a.$componentTemplateNodes=p});r=l;a.hb(e,f)}})},null,{i:f});return{controlsDescendantBindings:!0}}};a.f.aa.component=!0})();var Q={"class":"className","for":"htmlFor"};a.d.attr={update:function(b,c){var d=a.a.c(c())||{};a.a.D(d,function(c,d){d=a.a.c(d);var g=!1===d||null===d||d===n;g&&b.removeAttribute(c);8>=a.a.C&&c in Q?(c=Q[c],g?b.removeAttribute(c):b[c]=d):g||b.setAttribute(c,d.toString());"name"===c&&a.a.vc(b,g?"":d.toString())})}};(function(){a.d.checked={after:["value","attr"],init:function(b,
|
||||
c,d){function e(){var e=b.checked,f=p?g():e;if(!a.xa.Va()&&(!l||e)){var h=a.l.w(c);if(k){var m=r?h.p():h;q!==f?(e&&(a.a.ra(m,f,!0),a.a.ra(m,q,!1)),q=f):a.a.ra(m,f,e);r&&a.Da(h)&&h(m)}else a.h.Ga(h,d,"checked",f,!0)}}function f(){var d=a.a.c(c());b.checked=k?0<=a.a.o(d,g()):h?d:g()===d}var g=a.rc(function(){return d.has("checkedValue")?a.a.c(d.get("checkedValue")):d.has("value")?a.a.c(d.get("value")):b.value}),h="checkbox"==b.type,l="radio"==b.type;if(h||l){var m=c(),k=h&&a.a.c(m)instanceof Array,
|
||||
r=!(k&&m.push&&m.splice),q=k?g():n,p=l||k;l&&!b.name&&a.d.uniqueName.init(b,function(){return!0});a.m(e,null,{i:b});a.a.q(b,"click",e);a.m(f,null,{i:b});m=n}}};a.h.ga.checked=!0;a.d.checkedValue={update:function(b,c){b.value=a.a.c(c())}}})();a.d.css={update:function(b,c){var d=a.a.c(c());null!==d&&"object"==typeof d?a.a.D(d,function(c,d){d=a.a.c(d);a.a.fb(b,c,d)}):(d=a.a.cb(String(d||"")),a.a.fb(b,b.__ko__cssValue,!1),b.__ko__cssValue=d,a.a.fb(b,d,!0))}};a.d.enable={update:function(b,c){var d=a.a.c(c());
|
||||
d&&b.disabled?b.removeAttribute("disabled"):d||b.disabled||(b.disabled=!0)}};a.d.disable={update:function(b,c){a.d.enable.update(b,function(){return!a.a.c(c())})}};a.d.event={init:function(b,c,d,e,f){var g=c()||{};a.a.D(g,function(g){"string"==typeof g&&a.a.q(b,g,function(b){var m,k=c()[g];if(k){try{var r=a.a.W(arguments);e=f.$data;r.unshift(e);m=k.apply(e,r)}finally{!0!==m&&(b.preventDefault?b.preventDefault():b.returnValue=!1)}!1===d.get(g+"Bubble")&&(b.cancelBubble=!0,b.stopPropagation&&b.stopPropagation())}})})}};
|
||||
a.d.foreach={mc:function(b){return function(){var c=b(),d=a.a.Bb(c);if(!d||"number"==typeof d.length)return{foreach:c,templateEngine:a.X.vb};a.a.c(c);return{foreach:d.data,as:d.as,includeDestroyed:d.includeDestroyed,afterAdd:d.afterAdd,beforeRemove:d.beforeRemove,afterRender:d.afterRender,beforeMove:d.beforeMove,afterMove:d.afterMove,templateEngine:a.X.vb}}},init:function(b,c){return a.d.template.init(b,a.d.foreach.mc(c))},update:function(b,c,d,e,f){return a.d.template.update(b,a.d.foreach.mc(c),
|
||||
d,e,f)}};a.h.va.foreach=!1;a.f.aa.foreach=!0;a.d.hasfocus={init:function(b,c,d){function e(e){b.__ko_hasfocusUpdating=!0;var f=b.ownerDocument;if("activeElement"in f){var g;try{g=f.activeElement}catch(k){g=f.body}e=g===b}f=c();a.h.Ga(f,d,"hasfocus",e,!0);b.__ko_hasfocusLastValue=e;b.__ko_hasfocusUpdating=!1}var f=e.bind(null,!0),g=e.bind(null,!1);a.a.q(b,"focus",f);a.a.q(b,"focusin",f);a.a.q(b,"blur",g);a.a.q(b,"focusout",g)},update:function(b,c){var d=!!a.a.c(c());b.__ko_hasfocusUpdating||b.__ko_hasfocusLastValue===
|
||||
d||(d?b.focus():b.blur(),!d&&b.__ko_hasfocusLastValue&&b.ownerDocument.body.focus(),a.l.w(a.a.Fa,null,[b,d?"focusin":"focusout"]))}};a.h.ga.hasfocus=!0;a.d.hasFocus=a.d.hasfocus;a.h.ga.hasFocus=!0;a.d.html={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Eb(b,c())}};K("if");K("ifnot",!1,!0);K("with",!0,!1,function(a,c){return a.ac(c)});var L={};a.d.options={init:function(b){if("select"!==a.a.A(b))throw Error("options binding applies only to SELECT elements");for(;0<
|
||||
b.length;)b.remove(0);return{controlsDescendantBindings:!0}},update:function(b,c,d){function e(){return a.a.Ma(b.options,function(a){return a.selected})}function f(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[b]:c}function g(c,e){if(A&&k)a.j.ja(b,a.a.c(d.get("value")),!0);else if(p.length){var f=0<=a.a.o(p,a.j.u(e[0]));a.a.wc(e[0],f);A&&!f&&a.l.w(a.a.Fa,null,[b,"change"])}}var h=b.multiple,l=0!=b.length&&h?b.scrollTop:null,m=a.a.c(c()),k=d.get("valueAllowUnset")&&d.has("value"),r=
|
||||
d.get("optionsIncludeDestroyed");c={};var q,p=[];k||(h?p=a.a.ib(e(),a.j.u):0<=b.selectedIndex&&p.push(a.j.u(b.options[b.selectedIndex])));m&&("undefined"==typeof m.length&&(m=[m]),q=a.a.Ma(m,function(b){return r||b===n||null===b||!a.a.c(b._destroy)}),d.has("optionsCaption")&&(m=a.a.c(d.get("optionsCaption")),null!==m&&m!==n&&q.unshift(L)));var A=!1;c.beforeRemove=function(a){b.removeChild(a)};m=g;d.has("optionsAfterRender")&&"function"==typeof d.get("optionsAfterRender")&&(m=function(b,c){g(0,c);
|
||||
a.l.w(d.get("optionsAfterRender"),null,[c[0],b!==L?b:n])});a.a.Db(b,q,function(c,e,g){g.length&&(p=!k&&g[0].selected?[a.j.u(g[0])]:[],A=!0);e=b.ownerDocument.createElement("option");c===L?(a.a.bb(e,d.get("optionsCaption")),a.j.ja(e,n)):(g=f(c,d.get("optionsValue"),c),a.j.ja(e,a.a.c(g)),c=f(c,d.get("optionsText"),g),a.a.bb(e,c));return[e]},c,m);a.l.w(function(){k?a.j.ja(b,a.a.c(d.get("value")),!0):(h?p.length&&e().length<p.length:p.length&&0<=b.selectedIndex?a.j.u(b.options[b.selectedIndex])!==p[0]:
|
||||
p.length||0<=b.selectedIndex)&&a.a.Fa(b,"change")});a.a.Sc(b);l&&20<Math.abs(l-b.scrollTop)&&(b.scrollTop=l)}};a.d.options.zb=a.a.e.J();a.d.selectedOptions={after:["options","foreach"],init:function(b,c,d){a.a.q(b,"change",function(){var e=c(),f=[];a.a.r(b.getElementsByTagName("option"),function(b){b.selected&&f.push(a.j.u(b))});a.h.Ga(e,d,"selectedOptions",f)})},update:function(b,c){if("select"!=a.a.A(b))throw Error("values binding applies only to SELECT elements");var d=a.a.c(c()),e=b.scrollTop;
|
||||
d&&"number"==typeof d.length&&a.a.r(b.getElementsByTagName("option"),function(b){var c=0<=a.a.o(d,a.j.u(b));b.selected!=c&&a.a.wc(b,c)});b.scrollTop=e}};a.h.ga.selectedOptions=!0;a.d.style={update:function(b,c){var d=a.a.c(c()||{});a.a.D(d,function(c,d){d=a.a.c(d);if(null===d||d===n||!1===d)d="";b.style[c]=d})}};a.d.submit={init:function(b,c,d,e,f){if("function"!=typeof c())throw Error("The value for a submit binding must be a function");a.a.q(b,"submit",function(a){var d,e=c();try{d=e.call(f.$data,
|
||||
b)}finally{!0!==d&&(a.preventDefault?a.preventDefault():a.returnValue=!1)}})}};a.d.text={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.bb(b,c())}};a.f.aa.text=!0;(function(){if(x&&x.navigator)var b=function(a){if(a)return parseFloat(a[1])},c=x.opera&&x.opera.version&&parseInt(x.opera.version()),d=x.navigator.userAgent,e=b(d.match(/^(?:(?!chrome).)*version\/([^ ]*) safari/i)),f=b(d.match(/Firefox\/([^ ]*)/));if(10>a.a.C)var g=a.a.e.J(),h=a.a.e.J(),l=function(b){var c=
|
||||
this.activeElement;(c=c&&a.a.e.get(c,h))&&c(b)},m=function(b,c){var d=b.ownerDocument;a.a.e.get(d,g)||(a.a.e.set(d,g,!0),a.a.q(d,"selectionchange",l));a.a.e.set(b,h,c)};a.d.textInput={init:function(b,d,g){function l(c,d){a.a.q(b,c,d)}function h(){var c=a.a.c(d());if(null===c||c===n)c="";u!==n&&c===u?a.a.setTimeout(h,4):b.value!==c&&(s=c,b.value=c)}function y(){t||(u=b.value,t=a.a.setTimeout(v,4))}function v(){clearTimeout(t);u=t=n;var c=b.value;s!==c&&(s=c,a.h.Ga(d(),g,"textInput",c))}var s=b.value,
|
||||
t,u,x=9==a.a.C?y:v;10>a.a.C?(l("propertychange",function(a){"value"===a.propertyName&&x(a)}),8==a.a.C&&(l("keyup",v),l("keydown",v)),8<=a.a.C&&(m(b,x),l("dragend",y))):(l("input",v),5>e&&"textarea"===a.a.A(b)?(l("keydown",y),l("paste",y),l("cut",y)):11>c?l("keydown",y):4>f&&(l("DOMAutoComplete",v),l("dragdrop",v),l("drop",v)));l("change",v);a.m(h,null,{i:b})}};a.h.ga.textInput=!0;a.d.textinput={preprocess:function(a,b,c){c("textInput",a)}}})();a.d.uniqueName={init:function(b,c){if(c()){var d="ko_unique_"+
|
||||
++a.d.uniqueName.Nc;a.a.vc(b,d)}}};a.d.uniqueName.Nc=0;a.d.value={after:["options","foreach"],init:function(b,c,d){if("input"!=b.tagName.toLowerCase()||"checkbox"!=b.type&&"radio"!=b.type){var e=["change"],f=d.get("valueUpdate"),g=!1,h=null;f&&("string"==typeof f&&(f=[f]),a.a.ta(e,f),e=a.a.Wb(e));var l=function(){h=null;g=!1;var e=c(),f=a.j.u(b);a.h.Ga(e,d,"value",f)};!a.a.C||"input"!=b.tagName.toLowerCase()||"text"!=b.type||"off"==b.autocomplete||b.form&&"off"==b.form.autocomplete||-1!=a.a.o(e,"propertychange")||
|
||||
(a.a.q(b,"propertychange",function(){g=!0}),a.a.q(b,"focus",function(){g=!1}),a.a.q(b,"blur",function(){g&&l()}));a.a.r(e,function(c){var d=l;a.a.sd(c,"after")&&(d=function(){h=a.j.u(b);a.a.setTimeout(l,0)},c=c.substring(5));a.a.q(b,c,d)});var m=function(){var e=a.a.c(c()),f=a.j.u(b);if(null!==h&&e===h)a.a.setTimeout(m,0);else if(e!==f)if("select"===a.a.A(b)){var g=d.get("valueAllowUnset"),f=function(){a.j.ja(b,e,g)};f();g||e===a.j.u(b)?a.a.setTimeout(f,0):a.l.w(a.a.Fa,null,[b,"change"])}else a.j.ja(b,
|
||||
e)};a.m(m,null,{i:b})}else a.La(b,{checkedValue:c})},update:function(){}};a.h.ga.value=!0;a.d.visible={update:function(b,c){var d=a.a.c(c()),e="none"!=b.style.display;d&&!e?b.style.display="":!d&&e&&(b.style.display="none")}};(function(b){a.d[b]={init:function(c,d,e,f,g){return a.d.event.init.call(this,c,function(){var a={};a[b]=d();return a},e,f,g)}}})("click");a.P=function(){};a.P.prototype.renderTemplateSource=function(){throw Error("Override renderTemplateSource");};a.P.prototype.createJavaScriptEvaluatorBlock=
|
||||
function(){throw Error("Override createJavaScriptEvaluatorBlock");};a.P.prototype.makeTemplateSource=function(b,c){if("string"==typeof b){c=c||t;var d=c.getElementById(b);if(!d)throw Error("Cannot find template with ID "+b);return new a.v.n(d)}if(1==b.nodeType||8==b.nodeType)return new a.v.sa(b);throw Error("Unknown template type: "+b);};a.P.prototype.renderTemplate=function(a,c,d,e){a=this.makeTemplateSource(a,e);return this.renderTemplateSource(a,c,d,e)};a.P.prototype.isTemplateRewritten=function(a,
|
||||
c){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(a,c).data("isRewritten")};a.P.prototype.rewriteTemplate=function(a,c,d){a=this.makeTemplateSource(a,d);c=c(a.text());a.text(c);a.data("isRewritten",!0)};a.b("templateEngine",a.P);a.Ib=function(){function b(b,c,d,h){b=a.h.Ab(b);for(var l=a.h.va,m=0;m<b.length;m++){var k=b[m].key;if(l.hasOwnProperty(k)){var r=l[k];if("function"===typeof r){if(k=r(b[m].value))throw Error(k);}else if(!r)throw Error("This template engine does not support the '"+
|
||||
k+"' binding within its templates");}}d="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+a.h.Xa(b,{valueAccessors:!0})+" } })()},'"+d.toLowerCase()+"')";return h.createJavaScriptEvaluatorBlock(d)+c}var c=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'|[^>]*))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,d=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{Tc:function(b,c,d){c.isTemplateRewritten(b,d)||c.rewriteTemplate(b,function(b){return a.Ib.jd(b,
|
||||
c)},d)},jd:function(a,f){return a.replace(c,function(a,c,d,e,k){return b(k,c,d,f)}).replace(d,function(a,c){return b(c,"\x3c!-- ko --\x3e","#comment",f)})},Jc:function(b,c){return a.N.yb(function(d,h){var l=d.nextSibling;l&&l.nodeName.toLowerCase()===c&&a.La(l,b,h)})}}}();a.b("__tr_ambtns",a.Ib.Jc);(function(){a.v={};a.v.n=function(b){if(this.n=b){var c=a.a.A(b);this.eb="script"===c?1:"textarea"===c?2:"template"==c&&b.content&&11===b.content.nodeType?3:4}};a.v.n.prototype.text=function(){var b=1===
|
||||
this.eb?"text":2===this.eb?"value":"innerHTML";if(0==arguments.length)return this.n[b];var c=arguments[0];"innerHTML"===b?a.a.Eb(this.n,c):this.n[b]=c};var b=a.a.e.J()+"_";a.v.n.prototype.data=function(c){if(1===arguments.length)return a.a.e.get(this.n,b+c);a.a.e.set(this.n,b+c,arguments[1])};var c=a.a.e.J();a.v.n.prototype.nodes=function(){var b=this.n;if(0==arguments.length)return(a.a.e.get(b,c)||{}).mb||(3===this.eb?b.content:4===this.eb?b:n);a.a.e.set(b,c,{mb:arguments[0]})};a.v.sa=function(a){this.n=
|
||||
a};a.v.sa.prototype=new a.v.n;a.v.sa.prototype.text=function(){if(0==arguments.length){var b=a.a.e.get(this.n,c)||{};b.Jb===n&&b.mb&&(b.Jb=b.mb.innerHTML);return b.Jb}a.a.e.set(this.n,c,{Jb:arguments[0]})};a.b("templateSources",a.v);a.b("templateSources.domElement",a.v.n);a.b("templateSources.anonymousTemplate",a.v.sa)})();(function(){function b(b,c,d){var e;for(c=a.f.nextSibling(c);b&&(e=b)!==c;)b=a.f.nextSibling(e),d(e,b)}function c(c,d){if(c.length){var e=c[0],f=c[c.length-1],g=e.parentNode,h=
|
||||
a.S.instance,n=h.preprocessNode;if(n){b(e,f,function(a,b){var c=a.previousSibling,d=n.call(h,a);d&&(a===e&&(e=d[0]||b),a===f&&(f=d[d.length-1]||c))});c.length=0;if(!e)return;e===f?c.push(e):(c.push(e,f),a.a.Ba(c,g))}b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.Ub(d,b)});b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.N.Cc(b,[d])});a.a.Ba(c,g)}}function d(a){return a.nodeType?a:0<a.length?a[0]:null}function e(b,e,f,h,q){q=q||{};var p=(b&&d(b)||f||{}).ownerDocument,n=q.templateEngine||g;
|
||||
a.Ib.Tc(f,n,p);f=n.renderTemplate(f,h,q,p);if("number"!=typeof f.length||0<f.length&&"number"!=typeof f[0].nodeType)throw Error("Template engine must return an array of DOM nodes");p=!1;switch(e){case "replaceChildren":a.f.fa(b,f);p=!0;break;case "replaceNode":a.a.uc(b,f);p=!0;break;case "ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+e);}p&&(c(f,h),q.afterRender&&a.l.w(q.afterRender,null,[f,h.$data]));return f}function f(b,c,d){return a.I(b)?b():"function"===typeof b?b(c,d):b}
|
||||
var g;a.Fb=function(b){if(b!=n&&!(b instanceof a.P))throw Error("templateEngine must inherit from ko.templateEngine");g=b};a.Cb=function(b,c,k,h,q){k=k||{};if((k.templateEngine||g)==n)throw Error("Set a template engine before calling renderTemplate");q=q||"replaceChildren";if(h){var p=d(h);return a.B(function(){var g=c&&c instanceof a.R?c:new a.R(c,null,null,null,{exportDependencies:!0}),n=f(b,g.$data,g),g=e(h,q,n,g,k);"replaceNode"==q&&(h=g,p=d(h))},null,{ya:function(){return!p||!a.a.qb(p)},i:p&&
|
||||
"replaceNode"==q?p.parentNode:p})}return a.N.yb(function(d){a.Cb(b,c,k,d,"replaceNode")})};a.pd=function(b,d,g,h,q){function p(a,b){c(b,t);g.afterRender&&g.afterRender(b,a);t=null}function s(a,c){t=q.createChildContext(a,g.as,function(a){a.$index=c});var d=f(b,a,t);return e(null,"ignoreTargetNode",d,t,g)}var t;return a.B(function(){var b=a.a.c(d)||[];"undefined"==typeof b.length&&(b=[b]);b=a.a.Ma(b,function(b){return g.includeDestroyed||b===n||null===b||!a.a.c(b._destroy)});a.l.w(a.a.Db,null,[h,b,
|
||||
s,g,p])},null,{i:h})};var h=a.a.e.J();a.d.template={init:function(b,c){var d=a.a.c(c());if("string"==typeof d||d.name)a.f.za(b);else{if("nodes"in d){if(d=d.nodes||[],a.I(d))throw Error('The "nodes" option must be a plain, non-observable array.');}else d=a.f.childNodes(b);d=a.a.nc(d);(new a.v.sa(b)).nodes(d)}return{controlsDescendantBindings:!0}},update:function(b,c,d,e,f){var g=c();c=a.a.c(g);d=!0;e=null;"string"==typeof c?c={}:(g=c.name,"if"in c&&(d=a.a.c(c["if"])),d&&"ifnot"in c&&(d=!a.a.c(c.ifnot)));
|
||||
"foreach"in c?e=a.pd(g||b,d&&c.foreach||[],c,b,f):d?(f="data"in c?f.ac(c.data,c.as):f,e=a.Cb(g||b,f,c,b)):a.f.za(b);f=e;(c=a.a.e.get(b,h))&&"function"==typeof c.k&&c.k();a.a.e.set(b,h,f&&f.ca()?f:n)}};a.h.va.template=function(b){b=a.h.Ab(b);return 1==b.length&&b[0].unknown||a.h.fd(b,"name")?null:"This template engine does not support anonymous templates nested within its templates"};a.f.aa.template=!0})();a.b("setTemplateEngine",a.Fb);a.b("renderTemplate",a.Cb);a.a.hc=function(a,c,d){if(a.length&&
|
||||
c.length){var e,f,g,h,l;for(e=f=0;(!d||e<d)&&(h=a[f]);++f){for(g=0;l=c[g];++g)if(h.value===l.value){h.moved=l.index;l.moved=h.index;c.splice(g,1);e=g=0;break}e+=g}}};a.a.lb=function(){function b(b,d,e,f,g){var h=Math.min,l=Math.max,m=[],k,n=b.length,q,p=d.length,s=p-n||1,t=n+p+1,v,u,x;for(k=0;k<=n;k++)for(u=v,m.push(v=[]),x=h(p,k+s),q=l(0,k-1);q<=x;q++)v[q]=q?k?b[k-1]===d[q-1]?u[q-1]:h(u[q]||t,v[q-1]||t)+1:q+1:k+1;h=[];l=[];s=[];k=n;for(q=p;k||q;)p=m[k][q]-1,q&&p===m[k][q-1]?l.push(h[h.length]={status:e,
|
||||
value:d[--q],index:q}):k&&p===m[k-1][q]?s.push(h[h.length]={status:f,value:b[--k],index:k}):(--q,--k,g.sparse||h.push({status:"retained",value:d[q]}));a.a.hc(s,l,!g.dontLimitMoves&&10*n);return h.reverse()}return function(a,d,e){e="boolean"===typeof e?{dontLimitMoves:e}:e||{};a=a||[];d=d||[];return a.length<d.length?b(a,d,"added","deleted",e):b(d,a,"deleted","added",e)}}();a.b("utils.compareArrays",a.a.lb);(function(){function b(b,c,d,h,l){var m=[],k=a.B(function(){var k=c(d,l,a.a.Ba(m,b))||[];0<
|
||||
m.length&&(a.a.uc(m,k),h&&a.l.w(h,null,[d,k,l]));m.length=0;a.a.ta(m,k)},null,{i:b,ya:function(){return!a.a.Tb(m)}});return{ea:m,B:k.ca()?k:n}}var c=a.a.e.J(),d=a.a.e.J();a.a.Db=function(e,f,g,h,l){function m(b,c){w=q[c];u!==c&&(D[b]=w);w.tb(u++);a.a.Ba(w.ea,e);t.push(w);z.push(w)}function k(b,c){if(b)for(var d=0,e=c.length;d<e;d++)c[d]&&a.a.r(c[d].ea,function(a){b(a,d,c[d].ka)})}f=f||[];h=h||{};var r=a.a.e.get(e,c)===n,q=a.a.e.get(e,c)||[],p=a.a.ib(q,function(a){return a.ka}),s=a.a.lb(p,f,h.dontLimitMoves),
|
||||
t=[],v=0,u=0,x=[],z=[];f=[];for(var D=[],p=[],w,C=0,B,E;B=s[C];C++)switch(E=B.moved,B.status){case "deleted":E===n&&(w=q[v],w.B&&(w.B.k(),w.B=n),a.a.Ba(w.ea,e).length&&(h.beforeRemove&&(t.push(w),z.push(w),w.ka===d?w=null:f[C]=w),w&&x.push.apply(x,w.ea)));v++;break;case "retained":m(C,v++);break;case "added":E!==n?m(C,E):(w={ka:B.value,tb:a.O(u++)},t.push(w),z.push(w),r||(p[C]=w))}a.a.e.set(e,c,t);k(h.beforeMove,D);a.a.r(x,h.beforeRemove?a.ba:a.removeNode);for(var C=0,r=a.f.firstChild(e),F;w=z[C];C++){w.ea||
|
||||
a.a.extend(w,b(e,g,w.ka,l,w.tb));for(v=0;s=w.ea[v];r=s.nextSibling,F=s,v++)s!==r&&a.f.kc(e,s,F);!w.ad&&l&&(l(w.ka,w.ea,w.tb),w.ad=!0)}k(h.beforeRemove,f);for(C=0;C<f.length;++C)f[C]&&(f[C].ka=d);k(h.afterMove,D);k(h.afterAdd,p)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",a.a.Db);a.X=function(){this.allowTemplateRewriting=!1};a.X.prototype=new a.P;a.X.prototype.renderTemplateSource=function(b,c,d,e){if(c=(9>a.a.C?0:b.nodes)?b.nodes():null)return a.a.W(c.cloneNode(!0).childNodes);b=b.text();
|
||||
return a.a.na(b,e)};a.X.vb=new a.X;a.Fb(a.X.vb);a.b("nativeTemplateEngine",a.X);(function(){a.xb=function(){var a=this.ed=function(){if(!u||!u.tmpl)return 0;try{if(0<=u.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=function(b,e,f,g){g=g||t;f=f||{};if(2>a)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var h=b.data("precompiled");h||(h=b.text()||"",h=u.template(null,"{{ko_with $item.koBindingContext}}"+
|
||||
h+"{{/ko_with}}"),b.data("precompiled",h));b=[e.$data];e=u.extend({koBindingContext:e},f.templateOptions);e=u.tmpl(h,b,e);e.appendTo(g.createElement("div"));u.fragments={};return e};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){t.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(u.tmpl.tag.ko_code={open:"__.push($1 || '');"},u.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};a.xb.prototype=
|
||||
new a.P;var b=new a.xb;0<b.ed&&a.Fb(b);a.b("jqueryTmplTemplateEngine",a.xb)})()})})();})();
|
||||
1
interfaces/Glitter/templates/static/javascripts/moment-2.26.0.min.js
vendored
Normal file
1
interfaces/Glitter/templates/static/javascripts/moment-2.26.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -9,52 +9,56 @@
|
||||
factory(global.moment)
|
||||
}(this, (function (moment) { 'use strict';
|
||||
|
||||
//! moment.js locale configuration
|
||||
|
||||
var da = moment.defineLocale('da', {
|
||||
months : 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split('_'),
|
||||
monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
|
||||
weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),
|
||||
weekdaysShort : 'søn_man_tir_ons_tor_fre_lør'.split('_'),
|
||||
weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
|
||||
longDateFormat : {
|
||||
LT : 'HH:mm',
|
||||
LTS : 'HH:mm:ss',
|
||||
L : 'DD.MM.YYYY',
|
||||
LL : 'D. MMMM YYYY',
|
||||
LLL : 'D. MMMM YYYY HH:mm',
|
||||
LLLL : 'dddd [d.] D. MMMM YYYY [kl.] HH:mm'
|
||||
},
|
||||
calendar : {
|
||||
sameDay : '[i dag kl.] LT',
|
||||
nextDay : '[i morgen kl.] LT',
|
||||
nextWeek : 'på dddd [kl.] LT',
|
||||
lastDay : '[i går kl.] LT',
|
||||
lastWeek : '[i] dddd[s kl.] LT',
|
||||
sameElse : 'L'
|
||||
},
|
||||
relativeTime : {
|
||||
future : 'om %s',
|
||||
past : '%s siden',
|
||||
s : 'få sekunder',
|
||||
m : 'et minut',
|
||||
mm : '%d minutter',
|
||||
h : 'en time',
|
||||
hh : '%d timer',
|
||||
d : 'en dag',
|
||||
dd : '%d dage',
|
||||
M : 'en måned',
|
||||
MM : '%d måneder',
|
||||
y : 'et år',
|
||||
yy : '%d år'
|
||||
},
|
||||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||||
ordinal : '%d.',
|
||||
week : {
|
||||
dow : 1, // Monday is the first day of the week.
|
||||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||||
}
|
||||
});
|
||||
var da = moment.defineLocale('da', {
|
||||
months: 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split(
|
||||
'_'
|
||||
),
|
||||
monthsShort: 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),
|
||||
weekdays: 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),
|
||||
weekdaysShort: 'søn_man_tir_ons_tor_fre_lør'.split('_'),
|
||||
weekdaysMin: 'sø_ma_ti_on_to_fr_lø'.split('_'),
|
||||
longDateFormat: {
|
||||
LT: 'HH:mm',
|
||||
LTS: 'HH:mm:ss',
|
||||
L: 'DD.MM.YYYY',
|
||||
LL: 'D. MMMM YYYY',
|
||||
LLL: 'D. MMMM YYYY HH:mm',
|
||||
LLLL: 'dddd [d.] D. MMMM YYYY [kl.] HH:mm',
|
||||
},
|
||||
calendar: {
|
||||
sameDay: '[i dag kl.] LT',
|
||||
nextDay: '[i morgen kl.] LT',
|
||||
nextWeek: 'på dddd [kl.] LT',
|
||||
lastDay: '[i går kl.] LT',
|
||||
lastWeek: '[i] dddd[s kl.] LT',
|
||||
sameElse: 'L',
|
||||
},
|
||||
relativeTime: {
|
||||
future: 'om %s',
|
||||
past: '%s siden',
|
||||
s: 'få sekunder',
|
||||
ss: '%d sekunder',
|
||||
m: 'et minut',
|
||||
mm: '%d minutter',
|
||||
h: 'en time',
|
||||
hh: '%d timer',
|
||||
d: 'en dag',
|
||||
dd: '%d dage',
|
||||
M: 'en måned',
|
||||
MM: '%d måneder',
|
||||
y: 'et år',
|
||||
yy: '%d år',
|
||||
},
|
||||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||||
ordinal: '%d.',
|
||||
week: {
|
||||
dow: 1, // Monday is the first day of the week.
|
||||
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||
},
|
||||
});
|
||||
|
||||
return da;
|
||||
return da;
|
||||
|
||||
})));
|
||||
|
||||
@@ -11,68 +11,76 @@
|
||||
factory(global.moment)
|
||||
}(this, (function (moment) { 'use strict';
|
||||
|
||||
//! moment.js locale configuration
|
||||
|
||||
function processRelativeTime(number, withoutSuffix, key, isFuture) {
|
||||
var format = {
|
||||
'm': ['eine Minute', 'einer Minute'],
|
||||
'h': ['eine Stunde', 'einer Stunde'],
|
||||
'd': ['ein Tag', 'einem Tag'],
|
||||
'dd': [number + ' Tage', number + ' Tagen'],
|
||||
'M': ['ein Monat', 'einem Monat'],
|
||||
'MM': [number + ' Monate', number + ' Monaten'],
|
||||
'y': ['ein Jahr', 'einem Jahr'],
|
||||
'yy': [number + ' Jahre', number + ' Jahren']
|
||||
};
|
||||
return withoutSuffix ? format[key][0] : format[key][1];
|
||||
}
|
||||
|
||||
var de = moment.defineLocale('de', {
|
||||
months : 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
|
||||
monthsShort : 'Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.'.split('_'),
|
||||
monthsParseExact : true,
|
||||
weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
|
||||
weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
|
||||
weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
|
||||
weekdaysParseExact : true,
|
||||
longDateFormat : {
|
||||
LT: 'HH:mm',
|
||||
LTS: 'HH:mm:ss',
|
||||
L : 'DD.MM.YYYY',
|
||||
LL : 'D. MMMM YYYY',
|
||||
LLL : 'D. MMMM YYYY HH:mm',
|
||||
LLLL : 'dddd, D. MMMM YYYY HH:mm'
|
||||
},
|
||||
calendar : {
|
||||
sameDay: '[heute um] LT [Uhr]',
|
||||
sameElse: 'L',
|
||||
nextDay: '[morgen um] LT [Uhr]',
|
||||
nextWeek: 'dddd [um] LT [Uhr]',
|
||||
lastDay: '[gestern um] LT [Uhr]',
|
||||
lastWeek: '[letzten] dddd [um] LT [Uhr]'
|
||||
},
|
||||
relativeTime : {
|
||||
future : 'in %s',
|
||||
past : 'vor %s',
|
||||
s : 'ein paar Sekunden',
|
||||
m : processRelativeTime,
|
||||
mm : '%d Minuten',
|
||||
h : processRelativeTime,
|
||||
hh : '%d Stunden',
|
||||
d : processRelativeTime,
|
||||
dd : processRelativeTime,
|
||||
M : processRelativeTime,
|
||||
MM : processRelativeTime,
|
||||
y : processRelativeTime,
|
||||
yy : processRelativeTime
|
||||
},
|
||||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||||
ordinal : '%d.',
|
||||
week : {
|
||||
dow : 1, // Monday is the first day of the week.
|
||||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||||
function processRelativeTime(number, withoutSuffix, key, isFuture) {
|
||||
var format = {
|
||||
m: ['eine Minute', 'einer Minute'],
|
||||
h: ['eine Stunde', 'einer Stunde'],
|
||||
d: ['ein Tag', 'einem Tag'],
|
||||
dd: [number + ' Tage', number + ' Tagen'],
|
||||
M: ['ein Monat', 'einem Monat'],
|
||||
MM: [number + ' Monate', number + ' Monaten'],
|
||||
y: ['ein Jahr', 'einem Jahr'],
|
||||
yy: [number + ' Jahre', number + ' Jahren'],
|
||||
};
|
||||
return withoutSuffix ? format[key][0] : format[key][1];
|
||||
}
|
||||
});
|
||||
|
||||
return de;
|
||||
var de = moment.defineLocale('de', {
|
||||
months: 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split(
|
||||
'_'
|
||||
),
|
||||
monthsShort: 'Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.'.split(
|
||||
'_'
|
||||
),
|
||||
monthsParseExact: true,
|
||||
weekdays: 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split(
|
||||
'_'
|
||||
),
|
||||
weekdaysShort: 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
|
||||
weekdaysMin: 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
|
||||
weekdaysParseExact: true,
|
||||
longDateFormat: {
|
||||
LT: 'HH:mm',
|
||||
LTS: 'HH:mm:ss',
|
||||
L: 'DD.MM.YYYY',
|
||||
LL: 'D. MMMM YYYY',
|
||||
LLL: 'D. MMMM YYYY HH:mm',
|
||||
LLLL: 'dddd, D. MMMM YYYY HH:mm',
|
||||
},
|
||||
calendar: {
|
||||
sameDay: '[heute um] LT [Uhr]',
|
||||
sameElse: 'L',
|
||||
nextDay: '[morgen um] LT [Uhr]',
|
||||
nextWeek: 'dddd [um] LT [Uhr]',
|
||||
lastDay: '[gestern um] LT [Uhr]',
|
||||
lastWeek: '[letzten] dddd [um] LT [Uhr]',
|
||||
},
|
||||
relativeTime: {
|
||||
future: 'in %s',
|
||||
past: 'vor %s',
|
||||
s: 'ein paar Sekunden',
|
||||
ss: '%d Sekunden',
|
||||
m: processRelativeTime,
|
||||
mm: '%d Minuten',
|
||||
h: processRelativeTime,
|
||||
hh: '%d Stunden',
|
||||
d: processRelativeTime,
|
||||
dd: processRelativeTime,
|
||||
M: processRelativeTime,
|
||||
MM: processRelativeTime,
|
||||
y: processRelativeTime,
|
||||
yy: processRelativeTime,
|
||||
},
|
||||
dayOfMonthOrdinalParse: /\d{1,2}\./,
|
||||
ordinal: '%d.',
|
||||
week: {
|
||||
dow: 1, // Monday is the first day of the week.
|
||||
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||
},
|
||||
});
|
||||
|
||||
return de;
|
||||
|
||||
})));
|
||||
|
||||
@@ -9,84 +9,107 @@
|
||||
factory(global.moment)
|
||||
}(this, (function (moment) { 'use strict';
|
||||
|
||||
//! moment.js locale configuration
|
||||
|
||||
var monthsShortDot = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_');
|
||||
var monthsShort = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_');
|
||||
var monthsShortDot = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split(
|
||||
'_'
|
||||
),
|
||||
monthsShort = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_'),
|
||||
monthsParse = [
|
||||
/^ene/i,
|
||||
/^feb/i,
|
||||
/^mar/i,
|
||||
/^abr/i,
|
||||
/^may/i,
|
||||
/^jun/i,
|
||||
/^jul/i,
|
||||
/^ago/i,
|
||||
/^sep/i,
|
||||
/^oct/i,
|
||||
/^nov/i,
|
||||
/^dic/i,
|
||||
],
|
||||
monthsRegex = /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;
|
||||
|
||||
var monthsParse = [/^ene/i, /^feb/i, /^mar/i, /^abr/i, /^may/i, /^jun/i, /^jul/i, /^ago/i, /^sep/i, /^oct/i, /^nov/i, /^dic/i];
|
||||
var monthsRegex = /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;
|
||||
var es = moment.defineLocale('es', {
|
||||
months: 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split(
|
||||
'_'
|
||||
),
|
||||
monthsShort: function (m, format) {
|
||||
if (!m) {
|
||||
return monthsShortDot;
|
||||
} else if (/-MMM-/.test(format)) {
|
||||
return monthsShort[m.month()];
|
||||
} else {
|
||||
return monthsShortDot[m.month()];
|
||||
}
|
||||
},
|
||||
monthsRegex: monthsRegex,
|
||||
monthsShortRegex: monthsRegex,
|
||||
monthsStrictRegex: /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,
|
||||
monthsShortStrictRegex: /^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,
|
||||
monthsParse: monthsParse,
|
||||
longMonthsParse: monthsParse,
|
||||
shortMonthsParse: monthsParse,
|
||||
weekdays: 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'),
|
||||
weekdaysShort: 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'),
|
||||
weekdaysMin: 'do_lu_ma_mi_ju_vi_sá'.split('_'),
|
||||
weekdaysParseExact: true,
|
||||
longDateFormat: {
|
||||
LT: 'H:mm',
|
||||
LTS: 'H:mm:ss',
|
||||
L: 'DD/MM/YYYY',
|
||||
LL: 'D [de] MMMM [de] YYYY',
|
||||
LLL: 'D [de] MMMM [de] YYYY H:mm',
|
||||
LLLL: 'dddd, D [de] MMMM [de] YYYY H:mm',
|
||||
},
|
||||
calendar: {
|
||||
sameDay: function () {
|
||||
return '[hoy a la' + (this.hours() !== 1 ? 's' : '') + '] LT';
|
||||
},
|
||||
nextDay: function () {
|
||||
return '[mañana a la' + (this.hours() !== 1 ? 's' : '') + '] LT';
|
||||
},
|
||||
nextWeek: function () {
|
||||
return 'dddd [a la' + (this.hours() !== 1 ? 's' : '') + '] LT';
|
||||
},
|
||||
lastDay: function () {
|
||||
return '[ayer a la' + (this.hours() !== 1 ? 's' : '') + '] LT';
|
||||
},
|
||||
lastWeek: function () {
|
||||
return (
|
||||
'[el] dddd [pasado a la' +
|
||||
(this.hours() !== 1 ? 's' : '') +
|
||||
'] LT'
|
||||
);
|
||||
},
|
||||
sameElse: 'L',
|
||||
},
|
||||
relativeTime: {
|
||||
future: 'en %s',
|
||||
past: 'hace %s',
|
||||
s: 'unos segundos',
|
||||
ss: '%d segundos',
|
||||
m: 'un minuto',
|
||||
mm: '%d minutos',
|
||||
h: 'una hora',
|
||||
hh: '%d horas',
|
||||
d: 'un día',
|
||||
dd: '%d días',
|
||||
M: 'un mes',
|
||||
MM: '%d meses',
|
||||
y: 'un año',
|
||||
yy: '%d años',
|
||||
},
|
||||
dayOfMonthOrdinalParse: /\d{1,2}º/,
|
||||
ordinal: '%dº',
|
||||
week: {
|
||||
dow: 1, // Monday is the first day of the week.
|
||||
doy: 4, // The week that contains Jan 4th is the first week of the year.
|
||||
},
|
||||
invalidDate: 'Fecha invalida',
|
||||
});
|
||||
|
||||
var es = moment.defineLocale('es', {
|
||||
months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'),
|
||||
monthsShort : function (m, format) {
|
||||
if (!m) {
|
||||
return monthsShortDot;
|
||||
} else if (/-MMM-/.test(format)) {
|
||||
return monthsShort[m.month()];
|
||||
} else {
|
||||
return monthsShortDot[m.month()];
|
||||
}
|
||||
},
|
||||
monthsRegex : monthsRegex,
|
||||
monthsShortRegex : monthsRegex,
|
||||
monthsStrictRegex : /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,
|
||||
monthsShortStrictRegex : /^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,
|
||||
monthsParse : monthsParse,
|
||||
longMonthsParse : monthsParse,
|
||||
shortMonthsParse : monthsParse,
|
||||
weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'),
|
||||
weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'),
|
||||
weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'),
|
||||
weekdaysParseExact : true,
|
||||
longDateFormat : {
|
||||
LT : 'H:mm',
|
||||
LTS : 'H:mm:ss',
|
||||
L : 'DD/MM/YYYY',
|
||||
LL : 'D [de] MMMM [de] YYYY',
|
||||
LLL : 'D [de] MMMM [de] YYYY H:mm',
|
||||
LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm'
|
||||
},
|
||||
calendar : {
|
||||
sameDay : function () {
|
||||
return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||||
},
|
||||
nextDay : function () {
|
||||
return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||||
},
|
||||
nextWeek : function () {
|
||||
return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||||
},
|
||||
lastDay : function () {
|
||||
return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||||
},
|
||||
lastWeek : function () {
|
||||
return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';
|
||||
},
|
||||
sameElse : 'L'
|
||||
},
|
||||
relativeTime : {
|
||||
future : 'en %s',
|
||||
past : 'hace %s',
|
||||
s : 'unos segundos',
|
||||
m : 'un minuto',
|
||||
mm : '%d minutos',
|
||||
h : 'una hora',
|
||||
hh : '%d horas',
|
||||
d : 'un día',
|
||||
dd : '%d días',
|
||||
M : 'un mes',
|
||||
MM : '%d meses',
|
||||
y : 'un año',
|
||||
yy : '%d años'
|
||||
},
|
||||
dayOfMonthOrdinalParse : /\d{1,2}º/,
|
||||
ordinal : '%dº',
|
||||
week : {
|
||||
dow : 1, // Monday is the first day of the week.
|
||||
doy : 4 // The week that contains Jan 4th is the first week of the year.
|
||||
}
|
||||
});
|
||||
|
||||
return es;
|
||||
return es;
|
||||
|
||||
})));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user