mirror of
https://github.com/sabnzbd/sabnzbd.git
synced 2026-01-04 13:41:00 -05:00
Compare commits
413 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46e1645289 | ||
|
|
4ce3965747 | ||
|
|
9d4af19db3 | ||
|
|
55f811289d | ||
|
|
fbb637e5e3 | ||
|
|
f628dda4e7 | ||
|
|
48e034f4be | ||
|
|
f8959baa2f | ||
|
|
8ed5997eae | ||
|
|
129d3eaf07 | ||
|
|
350db4afc0 | ||
|
|
0a8ffd233e | ||
|
|
a74b500e96 | ||
|
|
1298e7ccce | ||
|
|
e1c61c41ca | ||
|
|
3da76e15d2 | ||
|
|
b116c24b84 | ||
|
|
a43810ec46 | ||
|
|
d4954b52ec | ||
|
|
b0332e141c | ||
|
|
80a181816e | ||
|
|
0dec3b7ec3 | ||
|
|
2c92a7621c | ||
|
|
e05beb71e6 | ||
|
|
6d82c7e542 | ||
|
|
fb238af7de | ||
|
|
6b9e3cd9d8 | ||
|
|
0dd1f647d8 | ||
|
|
6999872ec3 | ||
|
|
83ccc0a765 | ||
|
|
bf4b06f620 | ||
|
|
8f290a11ce | ||
|
|
72fda0117f | ||
|
|
d1cfa51a46 | ||
|
|
d6a5f4c0dc | ||
|
|
124701c118 | ||
|
|
d1adc8abc1 | ||
|
|
0c2cfd6225 | ||
|
|
f280363df5 | ||
|
|
6ed9dcfc95 | ||
|
|
4008bd004f | ||
|
|
cbbdccca81 | ||
|
|
0168d8870c | ||
|
|
d6269099aa | ||
|
|
5548bd9c7e | ||
|
|
5c8483f393 | ||
|
|
b9a344992b | ||
|
|
a85a988b22 | ||
|
|
d9808a7550 | ||
|
|
92894e9301 | ||
|
|
e59a28b617 | ||
|
|
27429a1415 | ||
|
|
8f9e1b2eb7 | ||
|
|
663330e251 | ||
|
|
4432e5684a | ||
|
|
92ecc2d0d4 | ||
|
|
7ea897ef39 | ||
|
|
7a8df5ee91 | ||
|
|
4c851b458a | ||
|
|
43ad83cee4 | ||
|
|
6f69bfd9ce | ||
|
|
f2423fd8a1 | ||
|
|
845d5cbaf2 | ||
|
|
d1052ca7e0 | ||
|
|
d7c76a3b43 | ||
|
|
4c7f74b356 | ||
|
|
b3dc74a07b | ||
|
|
e9fa56a635 | ||
|
|
6729e94f14 | ||
|
|
71dc1b5310 | ||
|
|
fe8065a7ef | ||
|
|
60afb7f444 | ||
|
|
3945eafb76 | ||
|
|
763088e6a6 | ||
|
|
a6ac88d5da | ||
|
|
d35ebec8f9 | ||
|
|
aee2747220 | ||
|
|
eae68bd6ba | ||
|
|
1875cbcb52 | ||
|
|
92410fc1ef | ||
|
|
ee7e209a8b | ||
|
|
9bc1601939 | ||
|
|
190ec0a472 | ||
|
|
468f01d839 | ||
|
|
5bbbf602f9 | ||
|
|
b03d68b434 | ||
|
|
0298beac15 | ||
|
|
be6f047e31 | ||
|
|
e8206371e4 | ||
|
|
6609248fce | ||
|
|
0ae5c7f8aa | ||
|
|
02b6f63156 | ||
|
|
8ab3ebd5f6 | ||
|
|
2b665667af | ||
|
|
ad7fc240c7 | ||
|
|
aef878a0f2 | ||
|
|
2a967b62d9 | ||
|
|
19946684d5 | ||
|
|
4c5ca149ba | ||
|
|
54d6e0dc21 | ||
|
|
ecb1403776 | ||
|
|
7e5c6d1c04 | ||
|
|
96b140dee0 | ||
|
|
2e098b641f | ||
|
|
6678cb9d56 | ||
|
|
4b67405d16 | ||
|
|
7463a4abdc | ||
|
|
163523048b | ||
|
|
4892bc18f3 | ||
|
|
217b2436f2 | ||
|
|
a9247ba934 | ||
|
|
8b2a6ef825 | ||
|
|
320495671b | ||
|
|
5ab872afa0 | ||
|
|
7ecb31805e | ||
|
|
e8ebeb843c | ||
|
|
3840678913 | ||
|
|
da7082b17e | ||
|
|
6198f95e1e | ||
|
|
4075b1accb | ||
|
|
6d8a774443 | ||
|
|
76c7a6ce95 | ||
|
|
01bd0bdce0 | ||
|
|
fa908de6e9 | ||
|
|
f05a6c6f76 | ||
|
|
d86fb42d28 | ||
|
|
7a7ce47769 | ||
|
|
40e57845a7 | ||
|
|
884dedc9d1 | ||
|
|
8e1f4e14a2 | ||
|
|
1190742127 | ||
|
|
e6d481a2ba | ||
|
|
0958caf5ed | ||
|
|
e2761d967e | ||
|
|
b4f36be170 | ||
|
|
5e722b27f3 | ||
|
|
367a73ef29 | ||
|
|
9228bc28ff | ||
|
|
02e18be5e1 | ||
|
|
531ef59e0a | ||
|
|
54e03fb40a | ||
|
|
904bb9f85a | ||
|
|
b011e1a518 | ||
|
|
f83f71a950 | ||
|
|
4dbf5266ef | ||
|
|
05aac4e01e | ||
|
|
267c48f9a7 | ||
|
|
5168915a65 | ||
|
|
71017d0d55 | ||
|
|
a5db51a2c5 | ||
|
|
0bf2968e6a | ||
|
|
2ec5918f5e | ||
|
|
04f5a63cd7 | ||
|
|
43d8283f5b | ||
|
|
f8111121c4 | ||
|
|
b53b73c135 | ||
|
|
bd7b8a975b | ||
|
|
7ca765f276 | ||
|
|
b918a53af5 | ||
|
|
525809afc9 | ||
|
|
a7048cdc8e | ||
|
|
02888568bd | ||
|
|
203409f02f | ||
|
|
ecc8e6ac0e | ||
|
|
852636acda | ||
|
|
bc18369552 | ||
|
|
8f248a2219 | ||
|
|
0d8d5daff6 | ||
|
|
82857afed6 | ||
|
|
4e7f0a6a1e | ||
|
|
2a113f7f58 | ||
|
|
6b8b9e0238 | ||
|
|
1e3e4b4118 | ||
|
|
87dfbe34d4 | ||
|
|
c56bcfaf61 | ||
|
|
a947a1d88b | ||
|
|
ad0d5726ec | ||
|
|
c52ce58b6d | ||
|
|
a90356c6e7 | ||
|
|
5c78c7855b | ||
|
|
915ee650ee | ||
|
|
58bd12b083 | ||
|
|
ecc334360a | ||
|
|
309f8e0044 | ||
|
|
730652e3e1 | ||
|
|
1aed59d52e | ||
|
|
1f04343a4d | ||
|
|
70f8509f6e | ||
|
|
74a97296a5 | ||
|
|
45d3440443 | ||
|
|
c872ee16ab | ||
|
|
da473424f2 | ||
|
|
902f67ef02 | ||
|
|
3c87fd45c3 | ||
|
|
d0a258ce28 | ||
|
|
5c54b873bf | ||
|
|
5ca4811689 | ||
|
|
043e5966ff | ||
|
|
d69796d351 | ||
|
|
a2d5713477 | ||
|
|
29ec4d9a23 | ||
|
|
22517a7cd7 | ||
|
|
bcc4dd75cf | ||
|
|
97711ca82e | ||
|
|
e782237f27 | ||
|
|
52bb156c08 | ||
|
|
4361d82ddd | ||
|
|
017cf8f285 | ||
|
|
03cdf6ed5d | ||
|
|
cf347a8e90 | ||
|
|
f06afe43e1 | ||
|
|
fb301eb5c8 | ||
|
|
1562c3560b | ||
|
|
9813bc237f | ||
|
|
b39fe059c6 | ||
|
|
a56c770a8b | ||
|
|
e3bf0edad8 | ||
|
|
e35d9e4db3 | ||
|
|
c617d4321a | ||
|
|
0fd3a2881f | ||
|
|
0c1f7633de | ||
|
|
b7d5d49c84 | ||
|
|
9911b93ece | ||
|
|
eeaad00968 | ||
|
|
e1bb8459e3 | ||
|
|
65c3ac0cc0 | ||
|
|
413c02a80f | ||
|
|
80f118f304 | ||
|
|
5c0a10e16b | ||
|
|
d9b32261e7 | ||
|
|
8d8ce52193 | ||
|
|
1cc2e25cda | ||
|
|
4605c3fd30 | ||
|
|
ed7dc3f827 | ||
|
|
e69eeebdd8 | ||
|
|
5da5f1adc1 | ||
|
|
f47e92dec0 | ||
|
|
a894ca5171 | ||
|
|
5abe1140ae | ||
|
|
d34e14370c | ||
|
|
c4f4a3131c | ||
|
|
dcbd9b57f3 | ||
|
|
aad3b54a17 | ||
|
|
cde142a371 | ||
|
|
8bfc98ffc6 | ||
|
|
e46f21d566 | ||
|
|
0e45fdcdfd | ||
|
|
eec7af16d7 | ||
|
|
6532425902 | ||
|
|
44b896522c | ||
|
|
1b16ee44cb | ||
|
|
d5f608c28c | ||
|
|
555d8418e7 | ||
|
|
8c22e35da4 | ||
|
|
95a7924b31 | ||
|
|
5830bebd95 | ||
|
|
d32cf57c75 | ||
|
|
6d9242ebc5 | ||
|
|
cbc4f6a964 | ||
|
|
2a3b2b9556 | ||
|
|
53a219f12b | ||
|
|
48519dcfa0 | ||
|
|
92542c58fe | ||
|
|
7eafe730f9 | ||
|
|
494e72a996 | ||
|
|
84cc86f1d3 | ||
|
|
64479e2e5d | ||
|
|
13b523d9bd | ||
|
|
181881a21b | ||
|
|
86d11095ac | ||
|
|
927ba3cd9d | ||
|
|
6296fc1762 | ||
|
|
60fbe44724 | ||
|
|
29e45da431 | ||
|
|
d82e69eef4 | ||
|
|
8c7d557252 | ||
|
|
a56d6e5517 | ||
|
|
7548d9e975 | ||
|
|
b7e2bd9684 | ||
|
|
f0a243e3d3 | ||
|
|
6e108c9ef2 | ||
|
|
89edcc1924 | ||
|
|
8a6aca47a1 | ||
|
|
d03e5780b8 | ||
|
|
209d8f9b40 | ||
|
|
c257b1be3d | ||
|
|
2c48c8de2e | ||
|
|
a767ef6aed | ||
|
|
ad61d1dd03 | ||
|
|
33c3d187a0 | ||
|
|
4eb486d4e2 | ||
|
|
bfb6c167a4 | ||
|
|
44abf3bdf6 | ||
|
|
c950572592 | ||
|
|
3999cb13fd | ||
|
|
af65075f0c | ||
|
|
de2a2b465b | ||
|
|
cd7a77f02d | ||
|
|
f4a5394b63 | ||
|
|
3fb6a8dedb | ||
|
|
50c8f84eba | ||
|
|
2c7ecdee92 | ||
|
|
72390a793a | ||
|
|
04ad4e5d3e | ||
|
|
5ef9c6a433 | ||
|
|
e6baffc839 | ||
|
|
e361eb25a5 | ||
|
|
9b420e91c9 | ||
|
|
3a4bf971b2 | ||
|
|
1128691c5d | ||
|
|
15043aef3f | ||
|
|
2a3b4afa03 | ||
|
|
00a98efa81 | ||
|
|
f013dd7f0d | ||
|
|
7b91b1c769 | ||
|
|
5583cce322 | ||
|
|
b995c5f992 | ||
|
|
214ac4a53d | ||
|
|
fc7e87f0df | ||
|
|
c0f2f59fc1 | ||
|
|
b90a847a6f | ||
|
|
a58bb385f5 | ||
|
|
9754baeb1c | ||
|
|
ffcd154966 | ||
|
|
97cfe9488c | ||
|
|
374b6f616a | ||
|
|
e2f51595b6 | ||
|
|
04091a16aa | ||
|
|
9d9d2fd9a2 | ||
|
|
5746115331 | ||
|
|
42f1a4926c | ||
|
|
7d87fd461b | ||
|
|
1ba9976979 | ||
|
|
659c199043 | ||
|
|
81a3f53226 | ||
|
|
1cbff28f67 | ||
|
|
8e15acbf30 | ||
|
|
e07be60db6 | ||
|
|
539c9662ff | ||
|
|
b396014f8d | ||
|
|
1db32415b6 | ||
|
|
b24629db6b | ||
|
|
9b5cdcf8fb | ||
|
|
4831415d14 | ||
|
|
a4c51f0b20 | ||
|
|
ec3ba1fb93 | ||
|
|
61966f7036 | ||
|
|
4f69e81841 | ||
|
|
d0d90581df | ||
|
|
8ea5c27633 | ||
|
|
517500fdf3 | ||
|
|
c4c1c9b6ab | ||
|
|
2388889ede | ||
|
|
55cfe878d7 | ||
|
|
a2daaee468 | ||
|
|
2c360e395e | ||
|
|
399cfee594 | ||
|
|
be646ae6ab | ||
|
|
b470253d9f | ||
|
|
b83c493492 | ||
|
|
991277bb01 | ||
|
|
5626013b81 | ||
|
|
2810d37758 | ||
|
|
c2f08f01e0 | ||
|
|
17ff087e06 | ||
|
|
77de565b7c | ||
|
|
54d238aa4d | ||
|
|
379d09f8cc | ||
|
|
00de72b127 | ||
|
|
f9c84fa7dd | ||
|
|
c8e46691bb | ||
|
|
df1bb636e5 | ||
|
|
ff886fad0d | ||
|
|
6dbee7a413 | ||
|
|
3f8fcd7172 | ||
|
|
d94f7388e6 | ||
|
|
ad8b49fea8 | ||
|
|
ce00270c12 | ||
|
|
8c501f8f58 | ||
|
|
ce313ebc65 | ||
|
|
887ad881a2 | ||
|
|
ce40827552 | ||
|
|
2777d89482 | ||
|
|
727b300a0e | ||
|
|
652b021a8e | ||
|
|
fdf33acfbb | ||
|
|
b001bc9b6f | ||
|
|
8802cb1d8c | ||
|
|
e19a2fbae7 | ||
|
|
53e38f98f9 | ||
|
|
e783e227f6 | ||
|
|
f3dfbe4181 | ||
|
|
bcd8ca8bc4 | ||
|
|
816d6a63cd | ||
|
|
88d3f25700 | ||
|
|
80f69b11db | ||
|
|
81a11f20c8 | ||
|
|
9e2a839953 | ||
|
|
3cefcde270 | ||
|
|
87a1eacfe7 | ||
|
|
7cbc1a8419 | ||
|
|
7b5570eb0b | ||
|
|
1a43a4dcf0 | ||
|
|
2c2a6592c7 | ||
|
|
f31de6ee4e | ||
|
|
8fcd1f6b6c | ||
|
|
d7f3a473d7 | ||
|
|
ab2eb0c94e | ||
|
|
e51f4fc45a | ||
|
|
65278120e2 | ||
|
|
2eed355e9c | ||
|
|
018955f4d5 | ||
|
|
12fd63c1cf |
13
.gitignore
vendored
13
.gitignore
vendored
@@ -1,4 +1,4 @@
|
||||
#Compiled python
|
||||
# Compiled python
|
||||
*.py[cod]
|
||||
|
||||
# Working folders for Win build
|
||||
@@ -7,6 +7,13 @@ dist/
|
||||
locale/
|
||||
srcdist/
|
||||
|
||||
# Snapcraft
|
||||
parts/
|
||||
prime/
|
||||
stage/
|
||||
snap/.snapcraft/
|
||||
*.snap
|
||||
|
||||
# Generated email templates
|
||||
email/*.tmpl
|
||||
|
||||
@@ -16,12 +23,14 @@ SABnzbd*.exe
|
||||
SABnzbd*.gz
|
||||
SABnzbd*.dmg
|
||||
|
||||
# WingIDE project files
|
||||
# WingIDE/PyCharm project files
|
||||
*.wp[ru]
|
||||
.idea
|
||||
|
||||
# Testing folders
|
||||
.cache
|
||||
.xprocess
|
||||
tests/cache
|
||||
|
||||
# General junk
|
||||
*.keep
|
||||
|
||||
10
.lgtm.yml
Normal file
10
.lgtm.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
path_classifiers:
|
||||
oldinterfaces:
|
||||
- interfaces/smpl
|
||||
- interfaces/Plush
|
||||
library:
|
||||
- cherrypy
|
||||
- gntp
|
||||
- six
|
||||
- "*knockout*"
|
||||
- "**/*min*"
|
||||
42
.travis.yml
42
.travis.yml
@@ -1,15 +1,39 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
before_install:
|
||||
- sudo add-apt-repository ppa:jcfp -y
|
||||
- sudo apt-get update -q
|
||||
- sudo apt-get install sabnzbdplus -y
|
||||
# Include the host/username/password for the test-servers
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
language: python
|
||||
python: 2.7
|
||||
env:
|
||||
- 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=
|
||||
- os: osx
|
||||
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=
|
||||
addons:
|
||||
chrome: stable
|
||||
|
||||
before_script:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||
brew cask install chromedriver;
|
||||
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;
|
||||
|
||||
install:
|
||||
- pip install --upgrade -r tests/requirements.txt
|
||||
|
||||
script:
|
||||
- pytest
|
||||
- python ./tests/test_functional.py
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
on_failure: always
|
||||
on_failure: always
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
*******************************************
|
||||
*** This is SABnzbd 2.3.3 ***
|
||||
*** This is SABnzbd 2.3.9 ***
|
||||
*******************************************
|
||||
SABnzbd is an open-source cross-platform binary newsreader.
|
||||
It simplifies the process of downloading from Usenet dramatically,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
(c) Copyright 2007-2018 by "The SABnzbd-team" <team@sabnzbd.org>
|
||||
(c) Copyright 2007-2019 by "The SABnzbd-team" <team@sabnzbd.org>
|
||||
|
||||
The SABnzbd-team is:
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
SABnzbd 2.3.3
|
||||
SABnzbd 2.3.9
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
0) LICENSE
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
(c) Copyright 2007-2018 by "The SABnzbd-team" <team@sabnzbd.org>
|
||||
(c) Copyright 2007-2019 by "The SABnzbd-team" <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
|
||||
|
||||
@@ -66,3 +66,7 @@
|
||||
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-2018 by "The SABnzbd-team" <team@sabnzbd.org>
|
||||
(c) Copyright 2007-2019 by "The SABnzbd-team" <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
|
||||
|
||||
4
PKG-INFO
4
PKG-INFO
@@ -1,7 +1,7 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: SABnzbd
|
||||
Version: 2.3.3RC2
|
||||
Summary: SABnzbd-2.3.3RC2
|
||||
Version: 2.3.9RC2
|
||||
Summary: SABnzbd-2.3.9RC2
|
||||
Home-page: https://sabnzbd.org
|
||||
Author: The SABnzbd Team
|
||||
Author-email: team@sabnzbd.org
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
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)
|
||||
|
||||
SABnzbd is an Open Source Binary Newsreader written in Python.
|
||||
|
||||
It's totally free, incredibly easy to use, and works practically everywhere.
|
||||
@@ -21,7 +27,6 @@ Optional:
|
||||
- `python-cryptography` (enables certificate generation and detection of encrypted RAR-files during download)
|
||||
- `python-dbus` (enable option to Shutdown/Restart/Standby PC on queue finish)
|
||||
- `7zip`
|
||||
- `unzip`
|
||||
|
||||
Your package manager should supply these. If not, we've got links in our more in-depth [installation guide](https://github.com/sabnzbd/sabnzbd/blob/master/INSTALL.txt).
|
||||
|
||||
|
||||
57
README.mkd
57
README.mkd
@@ -1,44 +1,23 @@
|
||||
Release Notes - SABnzbd 2.3.3 RC 2
|
||||
Release Notes - SABnzbd 2.3.9 RC 2
|
||||
=========================================================
|
||||
|
||||
## Changes since 2.3.3 RC 1
|
||||
- Hostname check improved for IPv6 addresses
|
||||
- Category not correctly parsed when grabbing NZB from URL
|
||||
- Unpacked zip/7zip files were not sorted
|
||||
- Extended SAN list of newly generated self-signed certificates
|
||||
## Improvements and bug fixes since 2.3.9 RC 1
|
||||
- Duplicate job detection would not compare job names
|
||||
- Propagation delay could show even if it was not configured
|
||||
- Ignore Samples deleted all files of jobs containing the words Sample/Proof
|
||||
|
||||
## Changes since 2.3.3 Beta 1
|
||||
- SABYenc updated to 3.3.4 to fix (more) false-positive CRC errors
|
||||
- Failed URL fetches also trigger post-processing script (if configured)
|
||||
- Added option to disable "X-Frame-Options" HTTP-header
|
||||
- Added option to set maximum URL fetch retries
|
||||
|
||||
## Changes since 2.3.2
|
||||
- Introduce and enforce "host_whitelist" to reject DNS Rebinding attacks.
|
||||
If you access SABnzbd from a non-standard URL, you will need to add
|
||||
the hostname. More info: https://sabnzbd.org/hostname-check
|
||||
- SABYenc updated to 3.3.3 to fix false-positive CRC errors
|
||||
- SSL-Ciphers can now be set per-server
|
||||
- Added "X-Frame-Options" HTTP-header to prevent click-jacking
|
||||
- Added "httpOnly" HTTP-header to prevent script cookie access
|
||||
- Added "ignore_empty_files" option to not warn on empty files in NZB
|
||||
- Indicate that SMPL-skin is no longer supported
|
||||
- Removed undocumented "callback" option from API calls
|
||||
- macOS: 64bit version of unrar instead of 32bit
|
||||
- Windows: Set process priority of external processes (unpack/repair)
|
||||
- Windows: Default external process priority increased to "Normal"
|
||||
|
||||
## Bugfixes since 2.3.2
|
||||
- NZB's can be added via command-line but this was not shown in "--help"
|
||||
- Language-change via API would not only change language after restart
|
||||
- Correctly indicate that 99 is maximum server priority
|
||||
- Only show SSL-warning if it was actually tested
|
||||
- Media files with "password" in filename were detected as encrypted
|
||||
- Servers that could not be DNS-resolved could block the queue
|
||||
- Detect '502 Byte limit exceeded' as payment problem
|
||||
- Server load-balancing setting was ignored when testing server
|
||||
- Windows: MultiPar checksum errors during repair would result in crash
|
||||
- Windows: Update 7zip to 18.01
|
||||
## Improvements and bug fixes since 2.3.8
|
||||
- Warning "Unable to stop the unrar process" was shown too often
|
||||
- Direct Unpack could hang forever on unicode downloads
|
||||
- Test Download could fail if clicked on icon instead of button
|
||||
- Series Duplicate detection did not always work with Direct Unpack enabled
|
||||
- Adding job with non-existing category was not set to Default (*) category
|
||||
- Only delete completed jobs from history when using History Retention option
|
||||
- Renamed Server Load-balancing to Server IP address selection
|
||||
- Linux: remove sabnzbd.error.log file at start-up if it grew too large
|
||||
- Windows: double-click delay increased to avoid accidental pausing
|
||||
- Windows: update MultiPar to v1.3.0.5
|
||||
- Windows and macOS: update UnRar to 5.71
|
||||
|
||||
## Upgrading from 2.2.x and older
|
||||
- Finish queue
|
||||
@@ -64,4 +43,4 @@ Release Notes - SABnzbd 2.3.3 RC 2
|
||||
that automatically verify, repair, extract and clean up posts downloaded
|
||||
from Usenet.
|
||||
|
||||
(c) Copyright 2007-2018 by "The SABnzbd-team" \<team@sabnzbd.org\>
|
||||
(c) Copyright 2007-2019 by "The SABnzbd-team" \<team@sabnzbd.org\>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -20,7 +20,6 @@ if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
|
||||
print "Sorry, requires Python 2.6 or 2.7."
|
||||
sys.exit(1)
|
||||
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
|
||||
115
SABnzbd.py
115
SABnzbd.py
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -44,7 +44,7 @@ import re
|
||||
|
||||
try:
|
||||
import Cheetah
|
||||
if Cheetah.Version[0] != '2':
|
||||
if Cheetah.Version[0] < '2':
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
print "Sorry, requires Python module Cheetah 2.0rc7 or higher."
|
||||
@@ -89,7 +89,7 @@ import sabnzbd.newsunpack
|
||||
from sabnzbd.misc import real_path, \
|
||||
check_latest_version, exit_sab, get_from_url, \
|
||||
split_host, get_ext, create_https_certificates, \
|
||||
windows_variant, ip_extract, set_serv_parms, get_serv_parms, globber_full
|
||||
windows_variant, ip_extract, set_serv_parms, get_serv_parms, globber_full, remove_file
|
||||
from sabnzbd.panic import panic_tmpl, panic_port, panic_host, \
|
||||
panic_sqlite, panic, launch_a_browser
|
||||
import sabnzbd.scheduler as scheduler
|
||||
@@ -182,7 +182,7 @@ def print_help():
|
||||
print " -s --server <srv:port> Listen on server:port [*]"
|
||||
print " -t --templates <templ> Template directory [*]"
|
||||
print
|
||||
print " -l --logging <0..2> Set logging level (-1=off, 0= least, 2= most) [*]"
|
||||
print " -l --logging <-1..2> Set logging level (-1=off, 0= least, 2= most) [*]"
|
||||
print " -w --weblogging Enable cherrypy access logging"
|
||||
print
|
||||
print " -b --browser <0..1> Auto browser launch (0= off, 1= on) [*]"
|
||||
@@ -204,11 +204,12 @@ def print_help():
|
||||
print " --ipv6_hosting <0|1> Listen on IPv6 address [::1] [*]"
|
||||
print " --no-login Start with username and password reset"
|
||||
print " --log-all Log all article handling (for developers)"
|
||||
print " --disable-file-log Logging is only written to console"
|
||||
print " --console Force console logging for OSX app"
|
||||
print " --new Run a new instance of SABnzbd"
|
||||
print ""
|
||||
print "NZB (or related) file:"
|
||||
print " NZB or zipped NZB file, with extension .nzb, .zip, .rar, .gz, or .bz2"
|
||||
print " NZB or compressed NZB file, with extension .nzb, .zip, .rar, .7z, .gz, or .bz2"
|
||||
print ""
|
||||
|
||||
|
||||
@@ -216,7 +217,7 @@ def print_version():
|
||||
print """
|
||||
%s-%s
|
||||
|
||||
Copyright (C) 2007-2018, The SABnzbd-Team <team@sabnzbd.org>
|
||||
Copyright (C) 2007-2019, The SABnzbd-Team <team@sabnzbd.org>
|
||||
SABnzbd comes with ABSOLUTELY NO WARRANTY.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions. It is licensed under the
|
||||
@@ -501,7 +502,7 @@ def all_localhosts():
|
||||
def check_resolve(host):
|
||||
""" Return True if 'host' resolves """
|
||||
try:
|
||||
dummy = socket.getaddrinfo(host, None)
|
||||
socket.getaddrinfo(host, None)
|
||||
except:
|
||||
# Does not resolve
|
||||
return False
|
||||
@@ -597,7 +598,7 @@ def get_webhost(cherryhost, cherryport, https_port):
|
||||
cherryhost = cherryhost.strip('[]')
|
||||
else:
|
||||
try:
|
||||
info = socket.getaddrinfo(cherryhost, None)
|
||||
socket.getaddrinfo(cherryhost, None)
|
||||
except:
|
||||
cherryhost = cherryhost.strip('[]')
|
||||
|
||||
@@ -658,12 +659,12 @@ def attach_server(host, port, cert=None, key=None, chain=None):
|
||||
def is_sabnzbd_running(url):
|
||||
""" Return True when there's already a SABnzbd instance running. """
|
||||
try:
|
||||
url = '%s&mode=version' % (url)
|
||||
url = '%s&mode=version' % url
|
||||
# Do this without certificate verification, few installations will have that
|
||||
prev = sabnzbd.set_https_verification(False)
|
||||
ver = get_from_url(url)
|
||||
sabnzbd.set_https_verification(prev)
|
||||
return (ver and (re.search(r'\d+\.\d+\.', ver) or ver.strip() == sabnzbd.__version__))
|
||||
return ver and (re.search(r'\d+\.\d+\.', ver) or ver.strip() == sabnzbd.__version__)
|
||||
except:
|
||||
return False
|
||||
|
||||
@@ -727,7 +728,7 @@ def evaluate_inipath(path):
|
||||
return path
|
||||
|
||||
|
||||
def commandline_handler(frozen=True):
|
||||
def commandline_handler():
|
||||
""" Split win32-service commands are true parameters
|
||||
Returns:
|
||||
service, sab_opts, serv_opts, upload_nzbs
|
||||
@@ -760,7 +761,7 @@ def commandline_handler(frozen=True):
|
||||
opts, args = getopt.getopt(info, "phdvncwl:s:f:t:b:2:",
|
||||
['pause', 'help', 'daemon', 'nobrowser', 'clean', 'logging=',
|
||||
'weblogging', 'server=', 'templates', 'ipv6_hosting=',
|
||||
'template2', 'browser=', 'config-file=', 'force',
|
||||
'template2', 'browser=', 'config-file=', 'force', 'disable-file-log',
|
||||
'version', 'https=', 'autorestarted', 'repair', 'repair-all',
|
||||
'log-all', 'no-login', 'pid=', 'new', 'console', 'pidfile=',
|
||||
# Below Win32 Service options
|
||||
@@ -823,11 +824,11 @@ def main():
|
||||
cherrypylogging = None
|
||||
clean_up = False
|
||||
logging_level = None
|
||||
no_file_log = False
|
||||
web_dir = None
|
||||
vista_plus = False
|
||||
win64 = False
|
||||
repair = 0
|
||||
api_url = None
|
||||
no_login = False
|
||||
sabnzbd.RESTART_ARGS = [sys.argv[0]]
|
||||
pid_path = None
|
||||
@@ -863,9 +864,9 @@ def main():
|
||||
elif opt in ('-b', '--browser'):
|
||||
try:
|
||||
autobrowser = bool(int(arg))
|
||||
except:
|
||||
except ValueError:
|
||||
autobrowser = True
|
||||
elif opt in ('--autorestarted', ):
|
||||
elif opt == '--autorestarted':
|
||||
autorestarted = True
|
||||
elif opt in ('-c', '--clean'):
|
||||
clean_up = True
|
||||
@@ -884,34 +885,36 @@ def main():
|
||||
exit_sab(0)
|
||||
elif opt in ('-p', '--pause'):
|
||||
pause = True
|
||||
elif opt in ('--https',):
|
||||
elif opt == '--https':
|
||||
https_port = int(arg)
|
||||
sabnzbd.RESTART_ARGS.append(opt)
|
||||
sabnzbd.RESTART_ARGS.append(arg)
|
||||
elif opt in ('--repair',):
|
||||
elif opt == '--repair':
|
||||
repair = 1
|
||||
pause = True
|
||||
elif opt in ('--repair-all',):
|
||||
elif opt == '--repair-all':
|
||||
repair = 2
|
||||
pause = True
|
||||
elif opt in ('--log-all',):
|
||||
elif opt == '--log-all':
|
||||
sabnzbd.LOG_ALL = True
|
||||
elif opt in ('--no-login',):
|
||||
elif opt == '--disable-file-log':
|
||||
no_file_log = True
|
||||
elif opt == '--no-login':
|
||||
no_login = True
|
||||
elif opt in ('--pid',):
|
||||
elif opt == '--pid':
|
||||
pid_path = arg
|
||||
sabnzbd.RESTART_ARGS.append(opt)
|
||||
sabnzbd.RESTART_ARGS.append(arg)
|
||||
elif opt in ('--pidfile',):
|
||||
elif opt == '--pidfile':
|
||||
pid_file = arg
|
||||
sabnzbd.RESTART_ARGS.append(opt)
|
||||
sabnzbd.RESTART_ARGS.append(arg)
|
||||
elif opt in ('--new',):
|
||||
elif opt == '--new':
|
||||
new_instance = True
|
||||
elif opt in ('--console',):
|
||||
elif opt == '--console':
|
||||
sabnzbd.RESTART_ARGS.append(opt)
|
||||
osx_console = True
|
||||
elif opt in ('--ipv6_hosting',):
|
||||
elif opt == '--ipv6_hosting':
|
||||
ipv6_hosting = arg
|
||||
|
||||
sabnzbd.MY_FULLNAME = os.path.normpath(os.path.abspath(sabnzbd.MY_FULLNAME))
|
||||
@@ -1002,13 +1005,13 @@ def main():
|
||||
if enable_https and https_port:
|
||||
try:
|
||||
cherrypy.process.servers.check_port(cherryhost, https_port, timeout=0.05)
|
||||
except IOError, error:
|
||||
except IOError:
|
||||
Bail_Out(browserhost, cherryport)
|
||||
except:
|
||||
Bail_Out(browserhost, cherryport, '49')
|
||||
try:
|
||||
cherrypy.process.servers.check_port(cherryhost, cherryport, timeout=0.05)
|
||||
except IOError, error:
|
||||
except IOError:
|
||||
Bail_Out(browserhost, cherryport)
|
||||
except:
|
||||
Bail_Out(browserhost, cherryport, '49')
|
||||
@@ -1045,7 +1048,7 @@ def main():
|
||||
else:
|
||||
# In case HTTPS == HTTP port
|
||||
cherryport = newport
|
||||
sabnzbd.cfg.port.set(newport)
|
||||
sabnzbd.cfg.cherryport.set(newport)
|
||||
except:
|
||||
# Something else wrong, probably badly specified host
|
||||
Bail_Out(browserhost, cherryport, '49')
|
||||
@@ -1076,11 +1079,7 @@ def main():
|
||||
# We found a port, now we never check again
|
||||
sabnzbd.cfg.fixed_ports.set(True)
|
||||
|
||||
if logging_level is None:
|
||||
logging_level = sabnzbd.cfg.log_level()
|
||||
else:
|
||||
sabnzbd.cfg.log_level.set(logging_level)
|
||||
|
||||
# Logging-checks
|
||||
logdir = sabnzbd.cfg.log_dir.get_path()
|
||||
if fork and not logdir:
|
||||
print "Error:"
|
||||
@@ -1099,19 +1098,24 @@ def main():
|
||||
# Prevent the logger from raising exceptions
|
||||
# primarily to reduce the fallout of Python issue 4749
|
||||
logging.raiseExceptions = 0
|
||||
|
||||
# Log-related constants we always need
|
||||
if logging_level is None:
|
||||
logging_level = sabnzbd.cfg.log_level()
|
||||
else:
|
||||
sabnzbd.cfg.log_level.set(logging_level)
|
||||
sabnzbd.LOGFILE = os.path.join(logdir, DEF_LOG_FILE)
|
||||
logformat = '%(asctime)s::%(levelname)s::[%(module)s:%(lineno)d] %(message)s'
|
||||
logger.setLevel(LOGLEVELS[logging_level + 1])
|
||||
|
||||
try:
|
||||
rollover_log = logging.handlers.RotatingFileHandler(
|
||||
sabnzbd.LOGFILE, 'a+',
|
||||
sabnzbd.cfg.log_size.get_int(),
|
||||
sabnzbd.cfg.log_backups())
|
||||
|
||||
logformat = '%(asctime)s::%(levelname)s::[%(module)s:%(lineno)d] %(message)s'
|
||||
rollover_log.setFormatter(logging.Formatter(logformat))
|
||||
sabnzbd.LOGHANDLER = rollover_log
|
||||
logger.addHandler(rollover_log)
|
||||
logger.setLevel(LOGLEVELS[logging_level + 1])
|
||||
if not no_file_log:
|
||||
rollover_log = logging.handlers.RotatingFileHandler(
|
||||
sabnzbd.LOGFILE, 'a+',
|
||||
sabnzbd.cfg.log_size.get_int(),
|
||||
sabnzbd.cfg.log_backups())
|
||||
rollover_log.setFormatter(logging.Formatter(logformat))
|
||||
logger.addHandler(rollover_log)
|
||||
|
||||
except IOError:
|
||||
print "Error:"
|
||||
@@ -1122,8 +1126,14 @@ def main():
|
||||
try:
|
||||
x = sys.stderr.fileno
|
||||
x = sys.stdout.fileno
|
||||
ol_path = os.path.join(logdir, DEF_LOG_ERRFILE)
|
||||
out_log = file(ol_path, 'a+', 0)
|
||||
|
||||
# Get log file path and remove the log file if it got too large
|
||||
log_path = os.path.join(logdir, DEF_LOG_ERRFILE)
|
||||
if os.path.exists(log_path) and os.path.getsize(log_path) > sabnzbd.cfg.log_size.get_int():
|
||||
remove_file(log_path)
|
||||
|
||||
# Redirect stderr/stdout
|
||||
out_log = file(log_path, 'a+', 0)
|
||||
sys.stderr.flush()
|
||||
sys.stdout.flush()
|
||||
os.dup2(out_log.fileno(), sys.stderr.fileno())
|
||||
@@ -1141,6 +1151,8 @@ def main():
|
||||
console.setLevel(LOGLEVELS[logging_level + 1])
|
||||
console.setFormatter(logging.Formatter(logformat))
|
||||
logger.addHandler(console)
|
||||
if no_file_log:
|
||||
logging.info('Console logging only')
|
||||
if noConsoleLoggingOSX:
|
||||
logging.info('Console logging for OSX App disabled')
|
||||
so = file('/dev/null', 'a+')
|
||||
@@ -1173,7 +1185,7 @@ def main():
|
||||
logging.info('Preferred encoding = ERROR')
|
||||
preferredencoding = ''
|
||||
|
||||
# On Linux/FreeBSD/Unix "UTF-8" is strongly, strongly adviced:
|
||||
# On Linux/FreeBSD/Unix "UTF-8" is strongly, strongly advised:
|
||||
if not sabnzbd.WIN32 and not sabnzbd.DARWIN and not ('utf' in preferredencoding.lower() and '8' in preferredencoding.lower()):
|
||||
logging.warning(T("SABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads.") % preferredencoding)
|
||||
|
||||
@@ -1230,8 +1242,6 @@ def main():
|
||||
|
||||
if autobrowser is not None:
|
||||
sabnzbd.cfg.autobrowser.set(autobrowser)
|
||||
else:
|
||||
autobrowser = sabnzbd.cfg.autobrowser()
|
||||
|
||||
if not sabnzbd.WIN_SERVICE and not getattr(sys, 'frozen', None) == 'macosx_app':
|
||||
signal.signal(signal.SIGINT, sabnzbd.sig_handler)
|
||||
@@ -1365,8 +1375,11 @@ def main():
|
||||
staticcfg = {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(sabnzbd.WEB_DIR_CONFIG, 'staticcfg'), 'tools.staticdir.content_types': forced_mime_types}
|
||||
wizard_static = {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(sabnzbd.WIZARD_DIR, 'static'), 'tools.staticdir.content_types': forced_mime_types}
|
||||
|
||||
appconfig = {'/api': {'tools.basic_auth.on': False},
|
||||
'/rss': {'tools.basic_auth.on': False},
|
||||
appconfig = {'/api': {
|
||||
'tools.basic_auth.on': False,
|
||||
'tools.response_headers.on': True,
|
||||
'tools.response_headers.headers': [('Access-Control-Allow-Origin', '*')]
|
||||
},
|
||||
'/static': static,
|
||||
'/wizard/static': wizard_static,
|
||||
'/favicon.ico': {'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(sabnzbd.WEB_DIR_CONFIG, 'staticcfg', 'ico', 'favicon.ico')},
|
||||
@@ -1591,7 +1604,7 @@ if sabnzbd.WIN32:
|
||||
win32serviceutil.ServiceFramework.__init__(self, args)
|
||||
|
||||
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
|
||||
self.overlapped = pywintypes.OVERLAPPED() # @UndefinedVariable
|
||||
self.overlapped = pywintypes.OVERLAPPED()
|
||||
self.overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None)
|
||||
sabnzbd.WIN_SERVICE = self
|
||||
|
||||
|
||||
10
appveyor.yml
10
appveyor.yml
@@ -1,6 +1,14 @@
|
||||
environment:
|
||||
SAB_NEWSSERVER_HOST:
|
||||
secure: 6SvOPWr5ypJeoumXJAZh90DLpk4C/5UAvzwyX7OOUr4=
|
||||
SAB_NEWSSERVER_USER:
|
||||
secure: Ty3ZG8T5vnacqIFPj5j5hg==
|
||||
SAB_NEWSSERVER_PASSWORD:
|
||||
secure: bO3XHtWTleVF9AqRV/V/nA==
|
||||
|
||||
install:
|
||||
- pip install --upgrade -r tests/requirements.txt
|
||||
- pip install pypiwin32 subprocessww
|
||||
|
||||
build_script:
|
||||
- pytest
|
||||
- python ./tests/test_functional.py
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
|
||||
<div class="colmask">
|
||||
<div class="padding alt">
|
||||
<h5 class="copyright">Copyright © 2007-2018 The SABnzbd Team <<a href="mailto:team@sabnzbd.org">team@sabnzbd.org</a>></h5>
|
||||
<h5 class="copyright">Copyright © 2007-2019 The SABnzbd Team <<a href="mailto:team@sabnzbd.org">team@sabnzbd.org</a>></h5>
|
||||
<p class="copyright"><small>$T('yourRights')</small></p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -61,11 +61,6 @@
|
||||
<input type="checkbox" name="email_rss" id="email_rss" value="1" <!--#if int($email_rss) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-email_rss')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="email_dir">$T('opt-email_dir')</label>
|
||||
<input type="text" name="email_dir" id="email_dir" value="$email_dir" data-initialdir="$my_home" />
|
||||
<span class="desc">$T('explain-email_dir')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="email_server">$T('opt-email_server')</label>
|
||||
<input type="text" name="email_server" id="email_server" value="$email_server" />
|
||||
@@ -194,7 +189,7 @@
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="nscript_script">$T('opt-nscript_script')</label>
|
||||
<select name="nscript_script">
|
||||
<select name="nscript_script" id="nscript_script">
|
||||
<!--#for $sc in $scripts#-->
|
||||
<option value="$sc" <!--#if $nscript_script == $sc then 'selected="selected"' else ""#-->>$Tspec($sc)</option>
|
||||
<!--#end for#-->
|
||||
@@ -404,9 +399,6 @@
|
||||
|
||||
<script type="text/javascript">
|
||||
\$(document).ready(function(){
|
||||
// Autocomplete and filebrowser
|
||||
\$('#email_dir').typeahead().fileBrowser();
|
||||
|
||||
// Expand on enable
|
||||
\$('.col2 input[name$="enable"]').change(function() {
|
||||
if(this.checked) {
|
||||
|
||||
@@ -390,9 +390,10 @@
|
||||
<th class="no-sort">$T('link-download')</th>
|
||||
<th>$T('rss-filter')</th>
|
||||
<th>$T('size')</th>
|
||||
<th width="65%">$T('sort-title')</th>
|
||||
<th width="60%">$T('sort-title')</th>
|
||||
<th>$T('category')</th>
|
||||
<th class="default-sort">$T('nzo-age')</th>
|
||||
<th>$T('source')</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!--#for $job in $matched#-->
|
||||
@@ -411,6 +412,13 @@
|
||||
<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>
|
||||
<!--#else#-->
|
||||
<a class="favicon source-icon" href="$job['infourl']" target="_blank" style="background-image: url(//$job['baselink']/favicon.ico);" data-domain="$job['baselink']"></a>
|
||||
<!--#end if#-->
|
||||
</td>
|
||||
</tr>
|
||||
<!--#end for#-->
|
||||
</table>
|
||||
@@ -426,9 +434,10 @@
|
||||
<th class="no-sort">$T('link-download')</th>
|
||||
<th>$T('rss-filter')</th>
|
||||
<th>$T('size')</th>
|
||||
<th width="65%">$T('sort-title')</th>
|
||||
<th width="60%">$T('sort-title')</th>
|
||||
<th>$T('category')</th>
|
||||
<th class="default-sort">$T('nzo-age')</th>
|
||||
<th>$T('source')</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!--#for $job in $unmatched#-->
|
||||
@@ -447,6 +456,13 @@
|
||||
<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>
|
||||
<!--#else#-->
|
||||
<a class="favicon source-icon" href="$job['infourl']" target="_blank" style="background-image: url(//$job['baselink']/favicon.ico);" data-domain="$job['baselink']"></a>
|
||||
<!--#end if#-->
|
||||
</td>
|
||||
</tr>
|
||||
<!--#end for#-->
|
||||
</table>
|
||||
@@ -476,8 +492,10 @@
|
||||
<td>$job['title']</td>
|
||||
<td>$job['cat']</td>
|
||||
<td data-sort-value="$job['baselink']" title="$job['baselink']">
|
||||
<!--#if $job['baselink']#-->
|
||||
<!--#if not $job['infourl']#-->
|
||||
<div class="favicon source-icon" style="background-image: url(//$job['baselink']/favicon.ico);" data-domain="$job['baselink']"></div>
|
||||
<!--#else#-->
|
||||
<a class="favicon source-icon" href="$job['infourl']" target="_blank" style="background-image: url(//$job['baselink']/favicon.ico);" data-domain="$job['baselink']"></a>
|
||||
<!--#end if#-->
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -415,6 +415,8 @@
|
||||
// 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()
|
||||
})
|
||||
@@ -448,6 +450,8 @@
|
||||
\$(this).html(\$(this).html().replace("$T('showDetails')", "$T('hideDetails')"));
|
||||
} else {
|
||||
\$(this).html(\$(this).html().replace("$T('hideDetails')", "$T('showDetails')"));
|
||||
// Recalculate the charts if changed while details were open
|
||||
showCharts()
|
||||
}
|
||||
// Add coloring
|
||||
addRowColor()
|
||||
|
||||
@@ -4,16 +4,13 @@ body {
|
||||
}
|
||||
#logo {
|
||||
display: block;
|
||||
margin: auto;
|
||||
margin-top: 3px;
|
||||
margin: 3px auto auto;
|
||||
}
|
||||
|
||||
#content {
|
||||
color: #000;
|
||||
padding: 15px 20px 20px;
|
||||
padding: 65px 20px 20px;
|
||||
font-size: 13px;
|
||||
padding-top: 65px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.colmask {
|
||||
z-index: 20;
|
||||
@@ -529,7 +526,7 @@ tr.separator {
|
||||
}
|
||||
#filebrowser_modal .checkbox {
|
||||
float: left;
|
||||
margin: 8px 5px 0x;
|
||||
margin: 8px 5px 0px;
|
||||
}
|
||||
#filebrowser_modal .checkbox input {
|
||||
margin-top: 1px;
|
||||
@@ -576,6 +573,7 @@ h2.activeRSS {
|
||||
float: left;
|
||||
margin: 0 6px 0 2px;
|
||||
text-align: center;
|
||||
color: black !important;
|
||||
}
|
||||
.source-icon span {
|
||||
top: -3px;
|
||||
@@ -600,8 +598,7 @@ h2.activeRSS {
|
||||
padding-top: .4em;
|
||||
}
|
||||
#subscriptions .chk {
|
||||
padding: 5px;
|
||||
padding-top: 8px;
|
||||
padding: 8px 5px 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
#subscriptions .title {
|
||||
@@ -773,7 +770,6 @@ input[type=radio] {
|
||||
input[type="button"],
|
||||
input[type="submit"] {
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
display:inline-block;
|
||||
padding:6px 12px;
|
||||
margin-bottom: 0;
|
||||
@@ -784,7 +780,7 @@ input[type="submit"] {
|
||||
white-space:nowrap;
|
||||
vertical-align:middle;
|
||||
cursor:pointer;
|
||||
background-image:none;
|
||||
background: #fff none;
|
||||
border:1px solid #ccc;
|
||||
height: 34px;
|
||||
}
|
||||
@@ -1002,7 +998,7 @@ input[type="checkbox"] {
|
||||
}
|
||||
|
||||
.Servers .col2.server-disabled .label {
|
||||
color: ##777 !important;
|
||||
color: #777 !important;
|
||||
}
|
||||
|
||||
.Servers .col2 .label:nth-child(2) {
|
||||
@@ -1063,9 +1059,7 @@ input[type="checkbox"] {
|
||||
|
||||
.Servers .col2 label,
|
||||
.Email .col2 label {
|
||||
margin: 0;
|
||||
margin-left: 4px;
|
||||
margin-top: 2px;
|
||||
margin: 2px 0 0 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -1141,6 +1135,7 @@ input[type="checkbox"] {
|
||||
}
|
||||
.value-and-select select {
|
||||
min-width: 30px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.dotOne, .dotTwo, .dotThree {
|
||||
@@ -1341,9 +1336,7 @@ input[type="checkbox"] {
|
||||
}
|
||||
|
||||
.desc {
|
||||
margin: 0;
|
||||
margin-left: 3px;
|
||||
margin-top: 2px;
|
||||
margin: 2px 0 0 3px;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<!--#from sabnzbd.constants import VALID_ARCHIVES, VALID_NZB_FILES#-->
|
||||
<!--#set $file_exts = ', '.join(VALID_NZB_FILES + VALID_ARCHIVES)#-->
|
||||
<!-- Notifcation box -->
|
||||
<div class="main-notification-box" style="display: none">
|
||||
<div class="main-notification-box-uploading">
|
||||
@@ -137,6 +139,13 @@
|
||||
</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 test-download">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="row options-function-box">
|
||||
<div class="col-sm-6">
|
||||
@@ -426,7 +435,7 @@
|
||||
<form data-bind="submit: addNZBFromURL" 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="$T('Glitter-nzbFormats')">
|
||||
<div class="input-group" data-tooltip="true" data-placement="bottom" title="$file_exts">
|
||||
<input type="text" name="nzbURL" class="form-control" placeholder="$T('enterURL')" />
|
||||
<span class="input-group-btn">
|
||||
<input type="submit" name="Add" value="$T('add')" class="btn btn-default" />
|
||||
@@ -437,10 +446,10 @@
|
||||
<form data-bind="submit: addNZBFromFileForm" 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="$T('Glitter-nzbFormats')">
|
||||
<div class="input-group" data-tooltip="true" data-placement="bottom" title="$file_exts">
|
||||
<label class="btn btn-default btn-file">
|
||||
<span class="glyphicon glyphicon-file"></span> <em>$T('Glitter-chooseFile')…</em>
|
||||
<input type="file" multiple name="nzbFile" class="form-control" accept=".nzb,.rar,.zip,.gz,.bz2" data-bind="event : { change: updateBrowseLabel }" />
|
||||
<input type="file" multiple name="nzbFile" class="form-control" accept="$file_exts" data-bind="event : { change: updateBrowseLabel }" />
|
||||
</label>
|
||||
|
||||
<span class="input-group-btn">
|
||||
@@ -562,10 +571,10 @@
|
||||
<input type="hidden" name="retry_job_id" />
|
||||
<fieldset>
|
||||
<legend>$T('opt-extra-NZB')</legend>
|
||||
<div class="input-group input-group-addfile" data-tooltip="true" data-placement="bottom" title="$T('Glitter-nzbFormats')">
|
||||
<div class="input-group input-group-addfile" data-tooltip="true" data-placement="bottom" title="$file_exts">
|
||||
<label class="btn btn-default btn-file">
|
||||
<span class="glyphicon glyphicon-file"></span> <em>$T('Glitter-chooseFile')…</em>
|
||||
<input type="file" name="nzbFile" class="form-control" accept=".nzb,.rar,.zip,.gz,.bz2" data-bind="event : { change: updateBrowseLabel }" />
|
||||
<input type="file" name="nzbFile" class="form-control" accept="$file_exts" data-bind="event : { change: updateBrowseLabel }" />
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
@@ -633,7 +642,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<hr/>
|
||||
<p><small>Copyright (C) 2007-2018, The SABnzbd Team <team@sabnzbd.org><br/>$T('yourRights') </small></p>
|
||||
<p><small>Copyright (C) 2007-2019, The SABnzbd Team <team@sabnzbd.org><br/>$T('yourRights') </small></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -35,6 +35,6 @@
|
||||
<!--#else if float($mbleft) < 0.1#-->
|
||||
SABnzbd
|
||||
<!--#else#-->
|
||||
<!--#if float($kbpersec) > 1023 #-->$speed<!--#else#--><!--#echo "%.0f" % float($kbpersec)#--> K<!--#end if#-->B/s - $sizeleft $T('Glitter-left') - SABnzbd
|
||||
${speed}B/s - $sizeleft $T('Glitter-left') - SABnzbd
|
||||
<!--#end if#-->
|
||||
|||<!--#echo "%.0f" % float($kbpersec)#-->
|
||||
@@ -96,7 +96,7 @@ function ViewModel() {
|
||||
|
||||
// Dynamic speed text function
|
||||
self.speedText = ko.pureComputed(function() {
|
||||
return self.speed() + ' ' + (self.speedMetrics[self.speedMetric()] ? self.speedMetrics[self.speedMetric()] : "KB/s");
|
||||
return self.speed() + ' ' + (self.speedMetrics[self.speedMetric()] ? self.speedMetrics[self.speedMetric()] : "B/s");
|
||||
});
|
||||
|
||||
// Dynamic icon
|
||||
@@ -849,6 +849,30 @@ function ViewModel() {
|
||||
})
|
||||
}
|
||||
|
||||
// Download a test-NZB
|
||||
self.testDownload = function(data, event) {
|
||||
var nzbSize = $(event.target).data('size')
|
||||
|
||||
// Maybe it was a click on the icon?
|
||||
if(nzbSize == undefined) {
|
||||
nzbSize = $(event.target.parentElement).data('size')
|
||||
}
|
||||
|
||||
// Build request
|
||||
var theCall = {
|
||||
mode: "addurl",
|
||||
name: "https://sabnzbd.org/tests/test_download_" + nzbSize + ".nzb",
|
||||
priority: self.queue.priorityName["Force"]
|
||||
}
|
||||
|
||||
// Add
|
||||
callAPI(theCall).then(function(r) {
|
||||
// Hide and reset/refresh
|
||||
self.refresh()
|
||||
$("#modal-options").modal("hide");
|
||||
});
|
||||
}
|
||||
|
||||
// Unblock server
|
||||
self.unblockServer = function(servername) {
|
||||
callSpecialAPI("./status/unblock_server/", {
|
||||
|
||||
@@ -76,7 +76,7 @@ legend,
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
.navbar-collapse.in .dropdown-menu, {
|
||||
.navbar-collapse.in .dropdown-menu {
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,10 +105,7 @@ h2 {
|
||||
.navbar-logo {
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
margin-right: 12px;
|
||||
margin-left: 15px;
|
||||
margin-top: 4px;
|
||||
margin-bottom: -1px;
|
||||
margin: 4px 12px -1px 15px;
|
||||
}
|
||||
|
||||
.navbar-logo svg {
|
||||
@@ -288,8 +285,7 @@ li.dropdown {
|
||||
opacity: 0.9;
|
||||
color: black;
|
||||
z-index: 2000;
|
||||
padding: 1em;
|
||||
padding-top: 15%;
|
||||
padding: 15% 1em 1em;
|
||||
}
|
||||
|
||||
.main-filedrop.in span {
|
||||
@@ -721,8 +717,7 @@ td.delete .dropdown>a {
|
||||
|
||||
td.delete input[type="checkbox"],
|
||||
.add-nzb-inputbox-options input[type="checkbox"]{
|
||||
margin: 0;
|
||||
margin-bottom: -2px;
|
||||
margin: 0 0 -2px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -1155,8 +1150,7 @@ tr.queue-item>td:first-child>a {
|
||||
#history-options {
|
||||
margin-top: 0;
|
||||
margin-left: 10px;
|
||||
padding: 0;
|
||||
padding-left: 4px;
|
||||
padding: 0 0 0 4px;
|
||||
}
|
||||
|
||||
#history-options .hover-button {
|
||||
@@ -1425,6 +1419,14 @@ tr.queue-item>td:first-child>a {
|
||||
margin: 5px 0px 10px;
|
||||
}
|
||||
|
||||
#modal-options .test-download .btn {
|
||||
padding: 1px 5px;
|
||||
}
|
||||
|
||||
#modal-options #options-status .test-download .btn .glyphicon {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
#modal-options .options-function-box {
|
||||
margin-top: 5px;
|
||||
}
|
||||
@@ -1536,8 +1538,7 @@ tr.queue-item>td:first-child>a {
|
||||
|
||||
.add-nzb-inputbox span {
|
||||
display: inline-block;
|
||||
margin: 8px 2px 0px 5px;
|
||||
margin-left: -20px;
|
||||
margin: 8px 2px 0px -20px;
|
||||
}
|
||||
|
||||
.btn-file {
|
||||
@@ -1630,11 +1631,9 @@ input[name="nzbURL"] {
|
||||
|
||||
#modal-item-files .multioperations-selector {
|
||||
clear: left;
|
||||
margin: 0;
|
||||
float: left;
|
||||
padding: 5px 8px;
|
||||
margin-bottom: 5px;
|
||||
margin-right: 10px;
|
||||
margin: 0 10px 5px 0;
|
||||
border: 1px solid #cccccc;
|
||||
}
|
||||
|
||||
@@ -2045,9 +2044,8 @@ a:focus {
|
||||
right: 17px;
|
||||
display: inline-block;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid #ccc;
|
||||
border-bottom: 6px solid rgba(0, 0, 0, 0.2);
|
||||
border-left: 6px solid transparent;
|
||||
border-bottom-color: rgba(0, 0, 0, 0.2);
|
||||
content: '';
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
</table>
|
||||
<div class="sabnzbd_logo main_sprite_container sprite_sabnzbdplus_logo"></div>
|
||||
<p><strong>SABnzbd $T('version'):</strong> $version</p>
|
||||
<p><small>Copyright (C) 2008-2016, The SABnzbd Team <team@sabnzbd.org></small></p>
|
||||
<p><small>Copyright (C) 2008-2019, The SABnzbd Team <team@sabnzbd.org></small></p>
|
||||
<p><small>$T('yourRights')</small></p>
|
||||
</div>
|
||||
|
||||
|
||||
16146
interfaces/smpl/templates/static/MochiKit/MochiKit.js
vendored
16146
interfaces/smpl/templates/static/MochiKit/MochiKit.js
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,2 @@
|
||||
dojo.hostenv.conditionalLoadModule({"common": ["MochiKit.MochiKit"]});
|
||||
dojo.hostenv.moduleLoaded("MochiKit.*");
|
||||
dojo.hostenv.conditionalLoadModule({"common": ["MochiKit.MochiKit"]});
|
||||
dojo.hostenv.moduleLoaded("MochiKit.*");
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<div class="form-group">
|
||||
<label for="host" class="col-sm-4 control-label">$T('srv-host')</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" class="form-control" name="host" id="host" value="$host" placeholder="$T('wizard-example') news.giganews.com" />
|
||||
<input type="text" class="form-control" name="host" id="host" value="$host" placeholder="$T('wizard-example') news.newshosting.com" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
||||
@@ -88,19 +88,12 @@ label {
|
||||
float: right;
|
||||
margin: 0;
|
||||
}
|
||||
.sup {
|
||||
vertical-align: sup !important;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
.align-center {
|
||||
text-align: center;
|
||||
}
|
||||
.float-center {
|
||||
float: center;
|
||||
}
|
||||
.unselected,
|
||||
.selected {
|
||||
display: inline-block;
|
||||
@@ -123,9 +116,6 @@ label {
|
||||
.bigger {
|
||||
font-size: 14px;
|
||||
}
|
||||
.padded {
|
||||
padding: 12px;
|
||||
}
|
||||
.bigger input {
|
||||
font-size: 16px;
|
||||
}
|
||||
@@ -135,9 +125,6 @@ label {
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
.bigbutton {
|
||||
font-size: 18px !important;
|
||||
}
|
||||
.correct {
|
||||
border: 2px solid #00cc22;
|
||||
}
|
||||
@@ -153,7 +140,6 @@ label {
|
||||
.text-input-wide {
|
||||
width: 230px;
|
||||
}
|
||||
.text-input-thin,
|
||||
#server-hidden-settings input[type="number"] {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
<p><strong>$T('opt-complete_dir')</strong></p>
|
||||
<div class="quoteBlock">
|
||||
$complete_dir
|
||||
<a href="${access_url}config/folders" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
|
||||
<a href="${access_url}/config/folders#complete_dir" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
|
||||
</div>
|
||||
|
||||
<p><strong>$T('opt-download_dir')</strong></p>
|
||||
<div class="quoteBlock">
|
||||
$download_dir
|
||||
<a href="${access_url}config/folders" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
|
||||
<a href="${access_url}/config/folders#complete_dir" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
@@ -53,7 +53,7 @@ the various releases.
|
||||
2.4.2 2.4.1 2005 PSF yes
|
||||
2.4.3 2.4.2 2006 PSF yes
|
||||
2.5 2.4 2006 PSF yes
|
||||
2.5.1 2.5 2007 PSF yes
|
||||
2.7 2.6 2010 PSF yes
|
||||
|
||||
Footnotes:
|
||||
|
||||
@@ -89,9 +89,9 @@ license to reproduce, analyze, test, perform and/or display publicly,
|
||||
prepare derivative works, distribute, and otherwise use Python
|
||||
alone or in any derivative version, provided, however, that PSF's
|
||||
License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
|
||||
2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation;
|
||||
All Rights Reserved" are retained in Python alone or in any derivative
|
||||
version prepared by Licensee.
|
||||
2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation; All Rights
|
||||
Reserved" are retained in Python alone or in any derivative version
|
||||
prepared by Licensee.
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on
|
||||
or incorporates Python or any part thereof, and wants to make
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
The original author of SABnzbd based his work on Pynewsleecher by Freddy@madcowdesease.org.
|
||||
|
||||
Few parts of Pynewsleecher have survived the generations of SABnzbd in a
|
||||
recognizable form.
|
||||
Still, we wish to thank Freddy for his inspiration.
|
||||
|
||||
The home of the Pynewsleecher project:
|
||||
http://www.madcowdisease.org/mcd/pynewsleecher
|
||||
|
||||
The software does not carry any license information.
|
||||
|
||||
The original author of SABnzbd based his work on Pynewsleecher by Freddy@madcowdesease.org.
|
||||
|
||||
Few parts of Pynewsleecher have survived the generations of SABnzbd in a
|
||||
recognizable form.
|
||||
Still, we wish to thank Freddy for his inspiration.
|
||||
|
||||
The home of the Pynewsleecher project:
|
||||
http://www.madcowdisease.org/mcd/pynewsleecher
|
||||
|
||||
The software does not carry any license information.
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
On http://www.brunningonline.net/simon/blog/archives/001835.html,
|
||||
the author licensed SysTrayIcon.py under a variant of the WTFPL:
|
||||
|
||||
> Any road up, help yourself. Consider SysTrayIcon.py to be under an
|
||||
> "Aleister Crowley" style license - "Do what thou wilt shall be the
|
||||
> only law".
|
||||
>
|
||||
> Err, but don't sue me if it doesn't work. ;-)
|
||||
On http://www.brunningonline.net/simon/blog/archives/001835.html,
|
||||
the author licensed SysTrayIcon.py under a variant of the WTFPL:
|
||||
|
||||
> Any road up, help yourself. Consider SysTrayIcon.py to be under an
|
||||
> "Aleister Crowley" style license - "Do what thou wilt shall be the
|
||||
> only law".
|
||||
>
|
||||
> Err, but don't sue me if it doesn't work. ;-)
|
||||
|
||||
BIN
osx/unrar/unrar
BIN
osx/unrar/unrar
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# SABnzbd Translation Template file EMAIL
|
||||
# Copyright 2011-2018 The SABnzbd-Team
|
||||
# Copyright 2011-2019 The SABnzbd-Team
|
||||
# team@sabnzbd.org
|
||||
#
|
||||
msgid ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: shypike <Unknown>\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2018-11-27 23:39+0000\n"
|
||||
"Last-Translator: scootergrisen <scootergrisen@gmail.com>\n"
|
||||
"Language-Team: Danish <da@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
@@ -65,13 +65,13 @@ msgid ""
|
||||
"<!--#end if#-->\n"
|
||||
msgstr ""
|
||||
"##\n"
|
||||
"## Standard Email skabelon til SABnzbd\n"
|
||||
"## Dette er en Cheetah skabelon\n"
|
||||
"## Standard E-mail-skabelon til SABnzbd\n"
|
||||
"## Dette er en Cheetah-skabelon\n"
|
||||
"## Dokumentation: http://sabnzbd.wikidot.com/email-templates\n"
|
||||
"##\n"
|
||||
"## Linjeskift og blanktegn er betydelig!\n"
|
||||
"## Linjeskift og blanktegn har betydning!\n"
|
||||
"##\n"
|
||||
"## Disse er e-mail-headerne \n"
|
||||
"## Dette er e-mail-headerne \n"
|
||||
"To: $to\n"
|
||||
"From: $from\n"
|
||||
"Date: $date\n"
|
||||
@@ -79,7 +79,7 @@ msgstr ""
|
||||
"job $name\n"
|
||||
"X-priority: 5\n"
|
||||
"X-MS-priority: 5\n"
|
||||
"## Efter dette kommer body, den tomme linje kræves!\n"
|
||||
"## Herefter kommer kroppen, den tomme linje skal være der!\n"
|
||||
"\n"
|
||||
"Hej,\n"
|
||||
"<!--#if $status #-->\n"
|
||||
@@ -100,13 +100,13 @@ msgstr ""
|
||||
"<!--#end for#-->\n"
|
||||
"<!--#end for#-->\n"
|
||||
"<!--#if $script!=\"\" #-->\n"
|
||||
"Output fra bruger script \"$script\" (Exit code = $script_ret):\n"
|
||||
"Output fra brugerscriptet \"$script\" (Afslutningskode = $script_ret):\n"
|
||||
"$script_output\n"
|
||||
"<!--#end if#-->\n"
|
||||
"<!--#if $status #-->\n"
|
||||
"Enjoy!\n"
|
||||
"Hav det godt!\n"
|
||||
"<!--#else#-->\n"
|
||||
"Sorry!\n"
|
||||
"Beklager!\n"
|
||||
"<!--#end if#-->\n"
|
||||
|
||||
#: email/rss.tmpl:1
|
||||
@@ -138,25 +138,25 @@ msgid ""
|
||||
"Bye\n"
|
||||
msgstr ""
|
||||
"##\n"
|
||||
"## RSS Email skabelon til SABnzbd\n"
|
||||
"## Dette er Cheetah skabelon\n"
|
||||
"## RSS E-mail-skabelon til SABnzbd\n"
|
||||
"## Dette er en Cheetah-skabelon\n"
|
||||
"## Dokumentation: http://sabnzbd.wikidot.com/email-templates\n"
|
||||
"##\n"
|
||||
"## Linjeskift og blanktegn er betydelig!\n"
|
||||
"## Linjeskift og blanktegn har betydning!\n"
|
||||
"##\n"
|
||||
"## Dette er email headers\n"
|
||||
"## Dette er e-mai-headere\n"
|
||||
"To: $to\n"
|
||||
"From: $from\n"
|
||||
"Date: $date\n"
|
||||
"Subject: SABnzbd har tilføjet $antal jobs til køen\n"
|
||||
"X-priority: 5\n"
|
||||
"X-MS-priority: 5\n"
|
||||
"## Efter dette kommer body, den tomme linje kræves!\n"
|
||||
"## Herefter kommer kroppen, den tomme linje skal være der!\n"
|
||||
"\n"
|
||||
"Hej,\n"
|
||||
"\n"
|
||||
"SABnzbd har tilføjet $antal job(s) til køen.\n"
|
||||
"De er fra RSS feed \"$feed\".\n"
|
||||
"De er fra RSS-feedet \"$feed\".\n"
|
||||
"<!--#for $job in $jobs#-->\n"
|
||||
" $job <!--#slurp#-->\n"
|
||||
"<!--#end for#-->\n"
|
||||
@@ -189,24 +189,24 @@ msgid ""
|
||||
"Bye\n"
|
||||
msgstr ""
|
||||
"##\n"
|
||||
"## Dårlig URL Fetch E-mail skabelon for SABnzbd\n"
|
||||
"## Dette er en Cheetah skabelon\n"
|
||||
"## Dårlig URL-hentning af E-mail-skabelon til SABnzbd\n"
|
||||
"## Dette er en Cheetah-skabelon\n"
|
||||
"## Dokumentation: http://sabnzbd.wikidot.com/email-templates\n"
|
||||
"##\n"
|
||||
"## Linjeskift og blanktegn er betydelig!\n"
|
||||
"## Linjeskift og blanktegn har betydning!\n"
|
||||
"##\n"
|
||||
"## Dette er email headers\n"
|
||||
"## Dette er e-mail-headere\n"
|
||||
"To: $to\n"
|
||||
"From: $from\n"
|
||||
"Date: $date\n"
|
||||
"Subject: SABnzbd kunne ikke hente en NZB\n"
|
||||
"X-priority: 5\n"
|
||||
"X-MS-priority: 5\n"
|
||||
"## Efter dette kommer body, den tomme linje kræves!\n"
|
||||
"## Herefter kommer kroppen, den tomme linje skal være der!\n"
|
||||
"\n"
|
||||
"Hej,\n"
|
||||
"\n"
|
||||
"SABnzbd kunne ikke hente NZB fra $url.\n"
|
||||
"Fejl meddelelsen er: $msg\n"
|
||||
"Fejlmeddelelsen er: $msg\n"
|
||||
"\n"
|
||||
"Farvel\n"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: Thomas Lucke (Lucky) <Unknown>\n"
|
||||
"Language-Team: German <de@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: shypike <Unknown>\n"
|
||||
"Language-Team: Spanish <es@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: Matti Ylönen <Unknown>\n"
|
||||
"Language-Team: Finnish <fi@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: Fox Ace <Unknown>\n"
|
||||
"Language-Team: French <fr@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"PO-Revision-Date: 2017-08-01 16:45+0000\n"
|
||||
"Last-Translator: ION IL <Unknown>\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2019-01-21 15:26+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>\n"
|
||||
"Language-Team: Hebrew <he@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2019-01-22 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18856)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
@@ -91,9 +91,9 @@ msgstr ""
|
||||
"הורדו $size\n"
|
||||
"\n"
|
||||
":תוצאות העבודה\n"
|
||||
"<!--#for $stage ב $stages #-->\n"
|
||||
"<!--#for $stage in $stages #-->\n"
|
||||
"שלב $stage <!--#slurp#-->\n"
|
||||
"<!--#for $result ב $stages[$stage]#-->\n"
|
||||
"<!--#for $result in $stages[$stage]#-->\n"
|
||||
" $result <!--#slurp#-->\n"
|
||||
"<!--#end for#-->\n"
|
||||
"<!--#end for#-->\n"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Norwegian Bokmal <nb@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: shypike <Unknown>\n"
|
||||
"Language-Team: Dutch <nl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: Tomasz 'Zen' Napierala <tomasz@napierala.org>\n"
|
||||
"Language-Team: Polish <pl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: lrrosa <Unknown>\n"
|
||||
"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: nicusor <Unknown>\n"
|
||||
"Language-Team: Romanian <ro@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: Pavel Maryanov <Unknown>\n"
|
||||
"Language-Team: Russian <gnu@mx.ru>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2017-06-24 19:51+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>\n"
|
||||
"Language-Team: Launchpad Serbian Translators\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
"Language: sr\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2017-06-24 19:50+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>\n"
|
||||
"Language-Team: Swedish <sv@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:04+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2015-10-24 11:05+0000\n"
|
||||
"Last-Translator: shypike <Unknown>\n"
|
||||
"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:37+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
675
po/main/da.po
675
po/main/da.po
File diff suppressed because it is too large
Load Diff
449
po/main/de.po
449
po/main/de.po
File diff suppressed because it is too large
Load Diff
408
po/main/es.po
408
po/main/es.po
File diff suppressed because it is too large
Load Diff
407
po/main/fi.po
407
po/main/fi.po
File diff suppressed because it is too large
Load Diff
414
po/main/fr.po
414
po/main/fr.po
File diff suppressed because it is too large
Load Diff
519
po/main/he.po
519
po/main/he.po
File diff suppressed because it is too large
Load Diff
403
po/main/nb.po
403
po/main/nb.po
File diff suppressed because it is too large
Load Diff
410
po/main/nl.po
410
po/main/nl.po
File diff suppressed because it is too large
Load Diff
405
po/main/pl.po
405
po/main/pl.po
File diff suppressed because it is too large
Load Diff
403
po/main/pt_BR.po
403
po/main/pt_BR.po
File diff suppressed because it is too large
Load Diff
406
po/main/ro.po
406
po/main/ro.po
File diff suppressed because it is too large
Load Diff
404
po/main/ru.po
404
po/main/ru.po
File diff suppressed because it is too large
Load Diff
403
po/main/sr.po
403
po/main/sr.po
File diff suppressed because it is too large
Load Diff
403
po/main/sv.po
403
po/main/sv.po
File diff suppressed because it is too large
Load Diff
403
po/main/zh_CN.po
403
po/main/zh_CN.po
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# SABnzbd Translation Template file NSIS
|
||||
# Copyright 2011-2018 The SABnzbd-Team
|
||||
# Copyright 2011-2019 The SABnzbd-Team
|
||||
# team@sabnzbd.org
|
||||
#
|
||||
msgid ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"PO-Revision-Date: 2017-04-10 11:28+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2018-11-27 23:30+0000\n"
|
||||
"Last-Translator: scootergrisen <scootergrisen@gmail.com>\n"
|
||||
"Language-Team: Danish <da@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
@@ -23,7 +23,7 @@ msgstr "Vis udgivelsesbemærkninger"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Start SABnzbd"
|
||||
msgstr ""
|
||||
msgstr "Start SABnzbd"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Support the project, Donate!"
|
||||
@@ -38,7 +38,7 @@ msgid ""
|
||||
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
|
||||
"run SABnzbd as a service, you need to update the service settings."
|
||||
msgstr ""
|
||||
"Installationsmappen er ændret (nu i \"Program Files \"). \\nHvis du kører "
|
||||
"Installationsmappen er ændret (nu i \"Program Files\"). \\nHvis du kører "
|
||||
"SABnzbd som en tjeneste, skal du opdatere tjenesteindstillingerne."
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
@@ -55,7 +55,7 @@ msgstr "Skrivebordsikon"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "NZB File association"
|
||||
msgstr "NZB filtilknytning"
|
||||
msgstr "NZB-filtilknytning"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Delete Program"
|
||||
@@ -70,20 +70,20 @@ msgid ""
|
||||
"This system requires the Microsoft runtime library VC90 to be installed "
|
||||
"first. Do you want to do that now?"
|
||||
msgstr ""
|
||||
"Dette system kræver, at Microsoft runtime biblioteket VC90 skal installeres "
|
||||
"først. Ønsker du at gøre det nu?"
|
||||
"Systemet kræver at Microsoft runtime-biblioteket VC90 skal installeres "
|
||||
"først. Vil du gøre det nu?"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Downloading Microsoft runtime installer..."
|
||||
msgstr "Downloader Microsoft runtime installationsfil..."
|
||||
msgstr "Downloader Microsoft runtime-installationsfil..."
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Download error, retry?"
|
||||
msgstr "Download fejl, prøv igen?"
|
||||
msgstr "Fejl ved download, prøv igen?"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Cannot install without runtime library, retry?"
|
||||
msgstr "Kan ikke installere uden runtime bibliotek, prøv igen?"
|
||||
msgstr "Kan ikke installere uden runtime-bibliotek, prøv igen?"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid ""
|
||||
@@ -91,8 +91,7 @@ msgid ""
|
||||
"the previous version or `Cancel` to cancel this upgrade."
|
||||
msgstr ""
|
||||
"Du kan ikke overskrive en eksisterende installation. \\n\\nKlik `OK` for at "
|
||||
"fjerne den tidligere version eller `Annuller` for at annullere denne "
|
||||
"opgradering."
|
||||
"fjerne den tidligere version eller `Annuller` for at annullere opgraderingen."
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Your settings and data will be preserved."
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2017-05-22 08:00+0000\n"
|
||||
"Last-Translator: larshuth <Unknown>\n"
|
||||
"Language-Team: German <de@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: Victor Herrero <victorhera@gmail.com>\n"
|
||||
"Language-Team: Spanish <es@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2017-04-02 07:38+0000\n"
|
||||
"Last-Translator: Paavo Rissanen <paavo.rissanen@outlook.com>\n"
|
||||
"Language-Team: Finnish <fi@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2017-03-21 08:58+0000\n"
|
||||
"Last-Translator: Fred <88com88@gmail.com>\n"
|
||||
"Language-Team: French <fr@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2017-05-06 09:07+0000\n"
|
||||
"Last-Translator: ION IL <Unknown>\n"
|
||||
"Language-Team: Hebrew <he@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Norwegian Bokmal <nb@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2017-03-19 09:47+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>\n"
|
||||
"Language-Team: Dutch <nl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: Tomasz 'Zen' Napierala <tomasz@napierala.org>\n"
|
||||
"Language-Team: Polish <pl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: lrrosa <Unknown>\n"
|
||||
"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: nicusor <Unknown>\n"
|
||||
"Language-Team: Romanian <ro@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: Pavel Maryanov <Unknown>\n"
|
||||
"Language-Team: Russian <gnu@mx.ru>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: Ozzii <Unknown>\n"
|
||||
"Language-Team: Launchpad Serbian Translators\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
"Language: sr\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: Andreas Lindberg <andypandyswe@gmail.com>\n"
|
||||
"Language-Team: Swedish <sv@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2018-03-15 13:05+0000\n"
|
||||
"POT-Creation-Date: 2018-12-24 11:01+0000\n"
|
||||
"PO-Revision-Date: 2017-05-28 17:17+0000\n"
|
||||
"Last-Translator: ninjai <ninjai.us@gmail.com>\n"
|
||||
"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2018-03-16 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build 18571)\n"
|
||||
"X-Launchpad-Export-Date: 2018-12-25 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build 18847)\n"
|
||||
|
||||
#: NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -202,7 +202,7 @@ def sig_handler(signum=None, frame=None):
|
||||
INIT_LOCK = Lock()
|
||||
|
||||
|
||||
def connect_db(thread_index=0):
|
||||
def get_db_connection(thread_index=0):
|
||||
# Create a connection and store it in the current thread
|
||||
if not (hasattr(cherrypy.thread_data, 'history_db') and cherrypy.thread_data.history_db):
|
||||
cherrypy.thread_data.history_db = sabnzbd.database.HistoryDB()
|
||||
@@ -223,7 +223,7 @@ def initialize(pause_downloader=False, clean_up=False, evalSched=False, repair=0
|
||||
__SHUTTING_DOWN__ = False
|
||||
|
||||
# Set global database connection for Web-UI threads
|
||||
cherrypy.engine.subscribe('start_thread', connect_db)
|
||||
cherrypy.engine.subscribe('start_thread', get_db_connection)
|
||||
|
||||
# Paused?
|
||||
pause_downloader = pause_downloader or cfg.start_paused()
|
||||
@@ -661,13 +661,13 @@ def add_nzbfile(nzbfile, pp=None, script=None, cat=None, priority=NORMAL_PRIORIT
|
||||
try:
|
||||
filename = nzbfile.filename.encode('cp1252').decode('utf-8')
|
||||
except:
|
||||
# Correct encoding afterall!
|
||||
# Correct encoding after all!
|
||||
filename = nzbfile.filename
|
||||
filename = encoding.special_fixer(filename)
|
||||
keep = False
|
||||
|
||||
if not sabnzbd.WIN32:
|
||||
# If windows client sends file to Unix server backslashed may
|
||||
# If windows client sends file to Unix server backslashes may
|
||||
# be included, so convert these
|
||||
filename = filename.replace('\\', '/')
|
||||
|
||||
@@ -963,9 +963,9 @@ def save_admin(data, _id):
|
||||
try:
|
||||
with open(path, 'wb') as data_file:
|
||||
if cfg.use_pickle():
|
||||
data = pickle.dump(data, data_file)
|
||||
pickle.dump(data, data_file)
|
||||
else:
|
||||
data = cPickle.dump(data, data_file)
|
||||
cPickle.dump(data, data_file)
|
||||
break
|
||||
except:
|
||||
if t == 2:
|
||||
@@ -1008,12 +1008,12 @@ def pp_to_opts(pp):
|
||||
# Convert the pp to an int
|
||||
pp = sabnzbd.interface.int_conv(pp)
|
||||
if pp == 0:
|
||||
return (False, False, False)
|
||||
return False, False, False
|
||||
if pp == 1:
|
||||
return (True, False, False)
|
||||
return True, False, False
|
||||
if pp == 2:
|
||||
return (True, True, False)
|
||||
return (True, True, True)
|
||||
return True, True, False
|
||||
return True, True, True
|
||||
|
||||
|
||||
def opts_to_pp(repair, unpack, delete):
|
||||
@@ -1195,6 +1195,10 @@ def test_cert_checking():
|
||||
On systems with at least Python > 2.7.9
|
||||
"""
|
||||
if sabnzbd.HAVE_SSL_CONTEXT:
|
||||
# User disabled the test, assume proper SSL certificates
|
||||
if not cfg.selftest_host():
|
||||
return True
|
||||
# Try a connection to our test-host
|
||||
try:
|
||||
import ssl
|
||||
ctx = ssl.create_default_context()
|
||||
@@ -1204,7 +1208,7 @@ def test_cert_checking():
|
||||
ssl_sock.connect((cfg.selftest_host(), 443))
|
||||
ssl_sock.close()
|
||||
return True
|
||||
except (socket.gaierror, socket.timeout) as e:
|
||||
except (socket.gaierror, socket.timeout):
|
||||
# Non-SSL related error.
|
||||
# We now assume that certificates work instead of forcing
|
||||
# lower quality just because some (temporary) internet problem
|
||||
|
||||
131
sabnzbd/api.py
131
sabnzbd/api.py
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -29,6 +29,7 @@ import cherrypy
|
||||
import locale
|
||||
|
||||
from threading import Thread
|
||||
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, "")
|
||||
except:
|
||||
@@ -42,8 +43,8 @@ except ImportError:
|
||||
|
||||
import sabnzbd
|
||||
from sabnzbd.constants import VALID_ARCHIVES, VALID_NZB_FILES, Status, \
|
||||
TOP_PRIORITY, REPAIR_PRIORITY, HIGH_PRIORITY, NORMAL_PRIORITY, LOW_PRIORITY, \
|
||||
KIBI, MEBI, GIGI, JOB_ADMIN
|
||||
TOP_PRIORITY, REPAIR_PRIORITY, HIGH_PRIORITY, NORMAL_PRIORITY, LOW_PRIORITY, \
|
||||
KIBI, MEBI, GIGI, JOB_ADMIN
|
||||
import sabnzbd.config as config
|
||||
import sabnzbd.cfg as cfg
|
||||
from sabnzbd.downloader import Downloader
|
||||
@@ -64,14 +65,12 @@ from sabnzbd.articlecache import ArticleCache
|
||||
from sabnzbd.utils.servertests import test_nntp_server_dict
|
||||
from sabnzbd.bpsmeter import BPSMeter
|
||||
from sabnzbd.rating import Rating
|
||||
from sabnzbd.getipaddress import localipv4, publicipv4, ipv6
|
||||
from sabnzbd.getipaddress import localipv4, publicipv4, ipv6, addresslookup
|
||||
from sabnzbd.newsunpack import userxbit
|
||||
from sabnzbd.database import build_history_info, unpack_history_info, HistoryDB
|
||||
import sabnzbd.notifier
|
||||
import sabnzbd.rss
|
||||
import sabnzbd.emailer
|
||||
import sabnzbd.getipaddress as getipaddress
|
||||
|
||||
|
||||
##############################################################################
|
||||
# API error messages
|
||||
@@ -87,7 +86,6 @@ _MSG_OUTPUT_FORMAT = 'Format not supported'
|
||||
_MSG_NO_SUCH_CONFIG = 'Config item does not exist'
|
||||
_MSG_BAD_SERVER_PARMS = 'Incorrect server settings'
|
||||
|
||||
|
||||
# For Windows: determine executable extensions
|
||||
if os.name == 'nt':
|
||||
PATHEXT = os.environ.get('PATHEXT', '').lower().split(';')
|
||||
@@ -220,6 +218,8 @@ def _api_queue_pause(output, value, kwargs):
|
||||
if value:
|
||||
items = value.split(',')
|
||||
handled = NzbQueue.do.pause_multiple_nzo(items)
|
||||
else:
|
||||
handled = False
|
||||
return report(output, keyword='', data={'status': bool(handled), 'nzo_ids': handled})
|
||||
|
||||
|
||||
@@ -228,6 +228,8 @@ def _api_queue_resume(output, value, kwargs):
|
||||
if value:
|
||||
items = value.split(',')
|
||||
handled = NzbQueue.do.resume_multiple_nzo(items)
|
||||
else:
|
||||
handled = False
|
||||
return report(output, keyword='', data={'status': bool(handled), 'nzo_ids': handled})
|
||||
|
||||
|
||||
@@ -341,7 +343,7 @@ def _api_addfile(name, output, kwargs):
|
||||
# Indexer category, so do mapping
|
||||
cat = cat_convert(xcat)
|
||||
res = sabnzbd.add_nzbfile(name, kwargs.get('pp'), kwargs.get('script'), cat,
|
||||
kwargs.get('priority'), kwargs.get('nzbname'))
|
||||
kwargs.get('priority'), kwargs.get('nzbname'))
|
||||
return report(output, keyword='', data={'status': res[0] == 0, 'nzo_ids': res[1]}, compat=True)
|
||||
else:
|
||||
return report(output, _MSG_NO_VALUE)
|
||||
@@ -462,6 +464,7 @@ def _api_change_opts(name, output, kwargs):
|
||||
""" API: accepts output, value(=nzo_id), value2(=pp) """
|
||||
value = kwargs.get('value')
|
||||
value2 = kwargs.get('value2')
|
||||
result = 0
|
||||
if value and value2 and value2.isdigit():
|
||||
result = NzbQueue.do.change_opts(value, int(value2))
|
||||
return report(output, keyword='status', data=bool(result > 0))
|
||||
@@ -483,7 +486,6 @@ def _api_history(name, output, kwargs):
|
||||
failed_only = kwargs.get('failed_only')
|
||||
categories = kwargs.get('category')
|
||||
|
||||
|
||||
# Do we need to send anything?
|
||||
if last_history_update == sabnzbd.LAST_HISTORY_UPDATE:
|
||||
return report(output, keyword='history', data=False)
|
||||
@@ -498,7 +500,7 @@ def _api_history(name, output, kwargs):
|
||||
special = value.lower()
|
||||
del_files = bool(int_conv(kwargs.get('del_files')))
|
||||
if special in ('all', 'failed', 'completed'):
|
||||
history_db = sabnzbd.connect_db()
|
||||
history_db = sabnzbd.get_db_connection()
|
||||
if special in ('all', 'failed'):
|
||||
if del_files:
|
||||
del_job_files(history_db.get_failed_paths(search))
|
||||
@@ -519,7 +521,7 @@ def _api_history(name, output, kwargs):
|
||||
history = {}
|
||||
grand, month, week, day = BPSMeter.do.get_sums()
|
||||
history['total_size'], history['month_size'], history['week_size'], history['day_size'] = \
|
||||
to_units(grand), to_units(month), to_units(week), to_units(day)
|
||||
to_units(grand), to_units(month), to_units(week), to_units(day)
|
||||
history['slots'], fetched_items, history['noofslots'] = build_history(start=start,
|
||||
limit=limit, verbose=True,
|
||||
search=search, failed_only=failed_only,
|
||||
@@ -724,9 +726,7 @@ def _api_reset_quota(name, output, kwargs):
|
||||
def _api_test_email(name, output, kwargs):
|
||||
""" API: send a test email, return result """
|
||||
logging.info("Sending test email")
|
||||
pack = {}
|
||||
pack['download'] = ['action 1', 'action 2']
|
||||
pack['unpack'] = ['action 1', 'action 2']
|
||||
pack = {'download': ['action 1', 'action 2'], 'unpack': ['action 1', 'action 2']}
|
||||
res = sabnzbd.emailer.endjob(u'I had a d\xe8ja vu', 'unknown', True,
|
||||
os.path.normpath(os.path.join(cfg.complete_dir.get_path(), u'/unknown/I had a d\xe8ja vu')),
|
||||
123 * MEBI, None, pack, 'my_script', u'Line 1\nLine 2\nLine 3\nd\xe8ja vu\n', 0,
|
||||
@@ -802,7 +802,6 @@ def _api_browse(name, output, kwargs):
|
||||
compact = kwargs.get('compact')
|
||||
|
||||
if compact and compact == '1':
|
||||
paths = []
|
||||
name = platform_encode(kwargs.get('term', ''))
|
||||
paths = [entry['path'] for entry in folders_at_path(os.path.dirname(name)) if 'path' in entry]
|
||||
return report(output, keyword='', data=paths)
|
||||
@@ -892,12 +891,11 @@ def _api_config_undefined(output, kwargs):
|
||||
def _api_server_stats(name, output, kwargs):
|
||||
""" API: accepts output """
|
||||
sum_t, sum_m, sum_w, sum_d = BPSMeter.do.get_sums()
|
||||
stats = {'total': sum_t, 'month': sum_m, 'week': sum_w, 'day': sum_d}
|
||||
stats = {'total': sum_t, 'month': sum_m, 'week': sum_w, 'day': sum_d, 'servers': {}}
|
||||
|
||||
stats['servers'] = {}
|
||||
for svr in config.get_servers():
|
||||
t, m, w, d, daily = BPSMeter.do.amounts(svr)
|
||||
stats['servers'][svr] = {'total': t or 0, 'month': m or 0, 'week': w or 0, 'day': d or 0, 'daily': daily or {} }
|
||||
stats['servers'][svr] = {'total': t or 0, 'month': m or 0, 'week': w or 0, 'day': d or 0, 'daily': daily or {}}
|
||||
|
||||
return report(output, keyword='', data=stats)
|
||||
|
||||
@@ -1150,6 +1148,24 @@ def handle_rss_api(output, kwargs):
|
||||
feed.set_dict(kwargs)
|
||||
else:
|
||||
config.ConfigRSS(name, kwargs)
|
||||
|
||||
action = kwargs.get('filter_action')
|
||||
if action in ('add', 'update'):
|
||||
# Use the general function, but catch the redirect-raise
|
||||
try:
|
||||
kwargs['feed'] = name
|
||||
sabnzbd.interface.ConfigRss('/').internal_upd_rss_filter(**kwargs)
|
||||
except cherrypy.HTTPRedirect:
|
||||
pass
|
||||
|
||||
elif action == 'delete':
|
||||
# Use the general function, but catch the redirect-raise
|
||||
try:
|
||||
kwargs['feed'] = name
|
||||
sabnzbd.interface.ConfigRss('/').internal_del_rss_filter(**kwargs)
|
||||
except cherrypy.HTTPRedirect:
|
||||
pass
|
||||
|
||||
return name
|
||||
|
||||
|
||||
@@ -1198,7 +1214,7 @@ def build_status(skip_dashboard=False, output=None):
|
||||
info['ipv6'] = ipv6()
|
||||
# Dashboard: DNS-check
|
||||
try:
|
||||
getipaddress.addresslookup(cfg.selftest_host())
|
||||
addresslookup(cfg.selftest_host())
|
||||
info['dnslookup'] = "OK"
|
||||
except:
|
||||
info['dnslookup'] = None
|
||||
@@ -1233,10 +1249,10 @@ def build_status(skip_dashboard=False, output=None):
|
||||
|
||||
# For the templates or for JSON
|
||||
if output:
|
||||
thread_info = { 'thrdnum': nw.thrdnum,
|
||||
'art_name': art_name,
|
||||
'nzf_name': nzf_name,
|
||||
'nzo_name': nzo_name }
|
||||
thread_info = {'thrdnum': nw.thrdnum,
|
||||
'art_name': art_name,
|
||||
'nzf_name': nzf_name,
|
||||
'nzo_name': nzo_name}
|
||||
serverconnections.append(thread_info)
|
||||
else:
|
||||
serverconnections.append((nw.thrdnum, art_name, nzf_name, nzo_name))
|
||||
@@ -1253,20 +1269,20 @@ def build_status(skip_dashboard=False, output=None):
|
||||
|
||||
# For the templates or for JSON
|
||||
if output:
|
||||
server_info = { 'servername': server.displayname,
|
||||
'serveractiveconn': connected,
|
||||
'servertotalconn': server.threads,
|
||||
'serverconnections': serverconnections,
|
||||
'serverssl': server.ssl,
|
||||
'serversslinfo': server.ssl_info,
|
||||
'serveractive': server.active,
|
||||
'servererror': server.errormsg,
|
||||
'serverpriority': server.priority,
|
||||
'serveroptional': server.optional }
|
||||
server_info = {'servername': server.displayname,
|
||||
'serveractiveconn': connected,
|
||||
'servertotalconn': server.threads,
|
||||
'serverconnections': serverconnections,
|
||||
'serverssl': server.ssl,
|
||||
'serversslinfo': server.ssl_info,
|
||||
'serveractive': server.active,
|
||||
'servererror': server.errormsg,
|
||||
'serverpriority': server.priority,
|
||||
'serveroptional': server.optional}
|
||||
info['servers'].append(server_info)
|
||||
else:
|
||||
info['servers'].append((server.displayname, '', connected, serverconnections, server.ssl,
|
||||
server.active, server.errormsg, server.priority, server.optional))
|
||||
server.active, server.errormsg, server.priority, server.optional))
|
||||
|
||||
info['warnings'] = sabnzbd.GUIHANDLER.content()
|
||||
|
||||
@@ -1346,10 +1362,10 @@ def build_queue(start=0, limit=0, trans=False, output=None, search=None):
|
||||
# Ensure compatibility of API status
|
||||
if status == Status.DELETED or priority == TOP_PRIORITY:
|
||||
status = Status.DOWNLOADING
|
||||
slot['status'] = "%s" % (status)
|
||||
slot['status'] = "%s" % status
|
||||
|
||||
if (Downloader.do.paused or Downloader.do.postproc or is_propagating or \
|
||||
status not in (Status.DOWNLOADING, Status.FETCHING, Status.QUEUED)) and priority != TOP_PRIORITY:
|
||||
if (Downloader.do.paused or Downloader.do.postproc or is_propagating or
|
||||
status not in (Status.DOWNLOADING, Status.FETCHING, Status.QUEUED)) and priority != TOP_PRIORITY:
|
||||
slot['timeleft'] = '0:00:00'
|
||||
slot['eta'] = 'unknown'
|
||||
else:
|
||||
@@ -1510,16 +1526,17 @@ def options_list(output):
|
||||
})
|
||||
|
||||
|
||||
def retry_job(job, new_nzb, password):
|
||||
def retry_job(job, new_nzb=None, password=None):
|
||||
""" Re enter failed job in the download queue """
|
||||
if job:
|
||||
history_db = sabnzbd.connect_db()
|
||||
history_db = sabnzbd.get_db_connection()
|
||||
futuretype, url, pp, script, cat = history_db.get_other(job)
|
||||
if futuretype:
|
||||
if pp == 'X':
|
||||
pp = None
|
||||
sabnzbd.add_url(url, pp, script, cat)
|
||||
nzo_id = sabnzbd.add_url(url, pp, script, cat)
|
||||
history_db.remove_history(job)
|
||||
return nzo_id
|
||||
else:
|
||||
path = history_db.get_path(job)
|
||||
if path:
|
||||
@@ -1531,8 +1548,13 @@ def retry_job(job, new_nzb, password):
|
||||
|
||||
def retry_all_jobs():
|
||||
""" Re enter all failed jobs in the download queue """
|
||||
history_db = sabnzbd.connect_db()
|
||||
return NzbQueue.do.retry_all_jobs(history_db)
|
||||
# Fetch all retryable folders from History
|
||||
items = sabnzbd.api.build_history()[0]
|
||||
nzo_ids = []
|
||||
for item in items:
|
||||
if item['retry']:
|
||||
nzo_ids.append(retry_job(item['nzo_id']))
|
||||
return nzo_ids
|
||||
|
||||
|
||||
def del_job_files(job_paths):
|
||||
@@ -1549,7 +1571,7 @@ def del_hist_job(job, del_files):
|
||||
if path:
|
||||
PostProcessor.do.delete(job, del_files=del_files)
|
||||
else:
|
||||
history_db = sabnzbd.connect_db()
|
||||
history_db = sabnzbd.get_db_connection()
|
||||
path = history_db.get_path(job)
|
||||
history_db.remove_history(job)
|
||||
|
||||
@@ -1568,7 +1590,9 @@ def Tspec(txt):
|
||||
return txt
|
||||
|
||||
|
||||
_SKIN_CACHE = {} # Stores pre-translated acronyms
|
||||
_SKIN_CACHE = {} # Stores pre-translated acronyms
|
||||
|
||||
|
||||
# This special is to be used in interface.py for template processing
|
||||
# to be passed for the $T function: so { ..., 'T' : Ttemplate, ...}
|
||||
def Ttemplate(txt):
|
||||
@@ -1685,7 +1709,6 @@ def build_queue_header(search=None, start=0, limit=0, output=None):
|
||||
header['size'] = format_bytes(bytes)
|
||||
header['noofslots_total'] = qnfo.q_fullsize
|
||||
|
||||
status = ''
|
||||
if Downloader.do.paused or Downloader.do.postproc:
|
||||
status = Status.PAUSED
|
||||
elif bytespersec > 0:
|
||||
@@ -1700,15 +1723,13 @@ def build_queue_header(search=None, start=0, limit=0, output=None):
|
||||
# new eta format: 16:00 Fri 07 Feb
|
||||
header['eta'] = datestart.strftime(time_format('%H:%M %a %d %b')).decode(codepage)
|
||||
except:
|
||||
datestart = datetime.datetime.now()
|
||||
header['eta'] = T('unknown')
|
||||
|
||||
return (header, qnfo.list, bytespersec, qnfo.q_fullsize, qnfo.bytes_left_previous_page)
|
||||
return header, qnfo.list, bytespersec, qnfo.q_fullsize, qnfo.bytes_left_previous_page
|
||||
|
||||
|
||||
def build_history(start=None, limit=None, verbose=False, verbose_list=None, search=None, failed_only=0,
|
||||
categories=None, output=None):
|
||||
|
||||
if output:
|
||||
converter = unicoder
|
||||
else:
|
||||
@@ -1761,7 +1782,7 @@ def build_history(start=None, limit=None, verbose=False, verbose_list=None, sear
|
||||
|
||||
# Aquire the db instance
|
||||
try:
|
||||
history_db = sabnzbd.connect_db()
|
||||
history_db = sabnzbd.get_db_connection()
|
||||
close_db = False
|
||||
except:
|
||||
# Required for repairs at startup because Cherrypy isn't active yet
|
||||
@@ -1772,7 +1793,6 @@ def build_history(start=None, limit=None, verbose=False, verbose_list=None, sear
|
||||
if not h_limit:
|
||||
items, fetched_items, total_items = history_db.fetch_history(h_start, 1, search, failed_only, categories)
|
||||
items = []
|
||||
fetched_items = 0
|
||||
else:
|
||||
items, fetched_items, total_items = history_db.fetch_history(h_start, h_limit, search, failed_only, categories)
|
||||
|
||||
@@ -1814,10 +1834,9 @@ def build_history(start=None, limit=None, verbose=False, verbose_list=None, sear
|
||||
item['show_details'] = 'True'
|
||||
else:
|
||||
item['show_details'] = ''
|
||||
if item['bytes']:
|
||||
item['size'] = format_bytes(item['bytes'])
|
||||
else:
|
||||
item['size'] = ''
|
||||
|
||||
item['size'] = format_bytes(item['bytes'])
|
||||
|
||||
if 'loaded' not in item:
|
||||
item['loaded'] = False
|
||||
|
||||
@@ -1857,7 +1876,7 @@ def build_history(start=None, limit=None, verbose=False, verbose_list=None, sear
|
||||
if close_db:
|
||||
history_db.close()
|
||||
|
||||
return (items, fetched_items, total_items)
|
||||
return items, fetched_items, total_items
|
||||
|
||||
|
||||
def get_active_history(queue=None, items=None):
|
||||
@@ -2013,7 +2032,6 @@ def history_remove_failed():
|
||||
del_job_files(history_db.get_failed_paths())
|
||||
history_db.remove_failed()
|
||||
history_db.close()
|
||||
del history_db
|
||||
|
||||
|
||||
def history_remove_completed():
|
||||
@@ -2022,4 +2040,3 @@ def history_remove_completed():
|
||||
history_db = HistoryDB()
|
||||
history_db.remove_completed()
|
||||
history_db.close()
|
||||
del history_db
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -28,9 +28,9 @@ from time import sleep
|
||||
import hashlib
|
||||
|
||||
import sabnzbd
|
||||
from sabnzbd.misc import get_filepath, sanitize_filename, get_unique_filename, renamer, \
|
||||
set_permissions, long_path, clip_path, has_win_device, get_all_passwords, diskspace, \
|
||||
get_filename, get_ext
|
||||
from sabnzbd.misc import get_filepath, sanitize_filename, set_permissions, \
|
||||
long_path, clip_path, has_win_device, get_all_passwords, diskspace, \
|
||||
get_filename, get_ext, is_rarfile
|
||||
from sabnzbd.constants import Status, GIGI
|
||||
import sabnzbd.cfg as cfg
|
||||
from sabnzbd.articlecache import ArticleCache
|
||||
@@ -81,11 +81,6 @@ class Assembler(Thread):
|
||||
# Abort all direct unpackers, just to be sure
|
||||
sabnzbd.directunpacker.abort_all()
|
||||
|
||||
# Place job back in queue and wait 30 seconds to hope it gets resolved
|
||||
self.process(job)
|
||||
sleep(30)
|
||||
continue
|
||||
|
||||
# Prepare filename
|
||||
nzo.verify_nzf_filename(nzf)
|
||||
nzf.filename = sanitize_filename(nzf.filename)
|
||||
@@ -117,7 +112,7 @@ class Assembler(Thread):
|
||||
nzf.remove_admin()
|
||||
|
||||
# Do rar-related processing
|
||||
if rarfile.is_rarfile(filepath):
|
||||
if is_rarfile(filepath):
|
||||
# Encryption and unwanted extension detection
|
||||
rar_encrypted, unwanted_file = check_encrypted_and_unwanted_files(nzo, filepath)
|
||||
if rar_encrypted:
|
||||
@@ -246,7 +241,7 @@ def check_encrypted_and_unwanted_files(nzo, filepath):
|
||||
return encrypted, unwanted
|
||||
|
||||
# Is it even a rarfile?
|
||||
if rarfile.is_rarfile(filepath):
|
||||
if is_rarfile(filepath):
|
||||
# Open the rar
|
||||
rarfile.UNRAR_TOOL = sabnzbd.newsunpack.RAR_COMMAND
|
||||
zf = rarfile.RarFile(filepath, all_names=True)
|
||||
@@ -334,11 +329,11 @@ def nzo_filtered_by_rating(nzo):
|
||||
nzo.rating_filtered = 1
|
||||
reason = rating_filtered(rating, nzo.filename.lower(), True)
|
||||
if reason is not None:
|
||||
return (2, reason)
|
||||
return 2, reason
|
||||
reason = rating_filtered(rating, nzo.filename.lower(), False)
|
||||
if reason is not None:
|
||||
return (1, reason)
|
||||
return (0, "")
|
||||
return 1, reason
|
||||
return 0, ""
|
||||
|
||||
|
||||
def rating_filtered(rating, filename, abort):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -26,7 +26,7 @@ from sabnzbd.constants import DEF_HOST, DEF_PORT, DEF_STDINTF, DEF_ADMIN_DIR, \
|
||||
|
||||
from sabnzbd.config import OptionBool, OptionNumber, OptionPassword, \
|
||||
OptionDir, OptionStr, OptionList, no_nonsense, \
|
||||
validate_octal, validate_safedir, \
|
||||
validate_octal, validate_safedir, all_lowercase, \
|
||||
create_api_key, validate_notempty
|
||||
|
||||
##############################################################################
|
||||
@@ -146,6 +146,7 @@ nice = OptionStr('misc', 'nice', '', validation=no_nonsense)
|
||||
win_process_prio = OptionNumber('misc', 'win_process_prio', 3)
|
||||
ionice = OptionStr('misc', 'ionice', '', validation=no_nonsense)
|
||||
fail_hopeless_jobs = OptionBool('misc', 'fail_hopeless_jobs', True)
|
||||
fast_fail = OptionBool('misc', 'fast_fail', True)
|
||||
autodisconnect = OptionBool('misc', 'auto_disconnect', True)
|
||||
no_dupes = OptionNumber('misc', 'no_dupes', 0)
|
||||
no_series_dupes = OptionNumber('misc', 'no_series_dupes', 0)
|
||||
@@ -265,6 +266,7 @@ no_penalties = OptionBool('misc', 'no_penalties', False)
|
||||
debug_log_decoding = OptionBool('misc', 'debug_log_decoding', False)
|
||||
ignore_empty_files = OptionBool('misc', 'ignore_empty_files', False)
|
||||
x_frame_options = OptionBool('misc', 'x_frame_options', True)
|
||||
require_modern_tls = OptionBool('misc', 'require_modern_tls', False)
|
||||
|
||||
# Text values
|
||||
rss_odd_titles = OptionList('misc', 'rss_odd_titles', ['nzbindex.nl/', 'nzbindex.com/', 'nzbclub.com/'])
|
||||
@@ -280,7 +282,7 @@ wait_ext_drive = OptionNumber('misc', 'wait_ext_drive', 5, 1, 60)
|
||||
marker_file = OptionStr('misc', 'nomedia_marker', '')
|
||||
ipv6_servers = OptionNumber('misc', 'ipv6_servers', 1, 0, 2)
|
||||
url_base = OptionStr('misc', 'url_base', '/sabnzbd')
|
||||
host_whitelist = OptionList('misc', 'host_whitelist')
|
||||
host_whitelist = OptionList('misc', 'host_whitelist', validation=all_lowercase)
|
||||
max_url_retries = OptionNumber('misc', 'max_url_retries', 10, 1)
|
||||
|
||||
##############################################################################
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -411,8 +411,8 @@ class ConfigServer(object):
|
||||
except KeyError:
|
||||
continue
|
||||
exec 'self.%s.set(value)' % kw
|
||||
if not self.displayname():
|
||||
self.displayname.set(self.__name)
|
||||
if not self.displayname():
|
||||
self.displayname.set(self.__name)
|
||||
return True
|
||||
|
||||
def get_dict(self, safe=False):
|
||||
@@ -463,7 +463,7 @@ class ConfigCat(object):
|
||||
self.pp = OptionStr(name, 'pp', '', add=False)
|
||||
self.script = OptionStr(name, 'script', 'Default', add=False)
|
||||
self.dir = OptionDir(name, 'dir', add=False, create=False)
|
||||
self.newzbin = OptionList(name, 'newzbin', add=False)
|
||||
self.newzbin = OptionList(name, 'newzbin', add=False, validation=validate_single_tag)
|
||||
self.priority = OptionNumber(name, 'priority', DEFAULT_PRIORITY, add=False)
|
||||
|
||||
self.set_dict(values)
|
||||
@@ -896,7 +896,7 @@ def get_servers():
|
||||
return {}
|
||||
|
||||
|
||||
def define_categories(force=False):
|
||||
def define_categories():
|
||||
""" Define categories listed in the Setup file
|
||||
return a list of ConfigCat instances
|
||||
"""
|
||||
@@ -990,7 +990,7 @@ def get_rss():
|
||||
for feed_uri in feed.uri():
|
||||
if new_feed_uris and not urlparse(feed_uri).scheme and urlparse(new_feed_uris[-1]).scheme:
|
||||
# Current one has no scheme but previous one does, append to previous
|
||||
new_feed_uris[-1] += '%2C' + feed_uri
|
||||
new_feed_uris[-1] += ',' + feed_uri
|
||||
have_new_uri = True
|
||||
continue
|
||||
# Add full working URL
|
||||
@@ -1054,6 +1054,14 @@ def no_nonsense(value):
|
||||
return None, value
|
||||
|
||||
|
||||
def all_lowercase(value):
|
||||
""" Lowercase everything! """
|
||||
if isinstance(value, list):
|
||||
# If list, for each item
|
||||
return None, [item.lower() for item in value]
|
||||
return None, value.lower()
|
||||
|
||||
|
||||
def validate_octal(value):
|
||||
""" Check if string is valid octal number """
|
||||
if not value:
|
||||
@@ -1094,6 +1102,16 @@ def validate_notempty(root, value, default):
|
||||
return None, default
|
||||
|
||||
|
||||
def validate_single_tag(value):
|
||||
""" Don't split single indexer tags like "TV > HD"
|
||||
into ['TV', '>', 'HD']
|
||||
"""
|
||||
if len(value) == 3:
|
||||
if value[1] == '>':
|
||||
return None, ' '.join(value)
|
||||
return None, value
|
||||
|
||||
|
||||
def create_api_key():
|
||||
""" Return a new randomized API_KEY """
|
||||
# Create some values to seed md5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -51,7 +51,7 @@ RENAMES_FILE = '__renames__'
|
||||
ATTRIB_FILE = 'SABnzbd_attrib'
|
||||
REPAIR_REQUEST = 'repair-all.sab'
|
||||
|
||||
SABYENC_VERSION_REQUIRED = '3.3.4'
|
||||
SABYENC_VERSION_REQUIRED = '3.3.5'
|
||||
|
||||
DB_HISTORY_VERSION = 1
|
||||
DB_HISTORY_NAME = 'history%s.db' % DB_HISTORY_VERSION
|
||||
@@ -123,7 +123,7 @@ year_match = r'[\W]([1|2]\d{3})([^\w]|$)' # Something '(YYYY)' or '.YYYY.' or '
|
||||
sample_match = r'((^|[\W_])(sample|proof))' # something-sample or something-proof
|
||||
|
||||
|
||||
class Status():
|
||||
class Status:
|
||||
COMPLETED = 'Completed' # PP: Job is finished
|
||||
CHECKING = 'Checking' # Q: Pre-check is running
|
||||
DOWNLOADING = 'Downloading' # Q: Normal downloading
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -36,11 +36,11 @@ import threading
|
||||
|
||||
import sabnzbd
|
||||
import sabnzbd.cfg
|
||||
from sabnzbd.constants import DB_HISTORY_NAME, STAGES
|
||||
from sabnzbd.constants import DB_HISTORY_NAME, STAGES, Status
|
||||
from sabnzbd.encoding import unicoder
|
||||
from sabnzbd.bpsmeter import this_week, this_month
|
||||
from sabnzbd.decorators import synchronized
|
||||
from sabnzbd.misc import get_all_passwords, int_conv, remove_file, caller_name
|
||||
from sabnzbd.misc import int_conv, remove_file, caller_name
|
||||
|
||||
DB_LOCK = threading.RLock()
|
||||
|
||||
@@ -118,7 +118,7 @@ class HistoryDB(object):
|
||||
self.execute('ALTER TABLE "history" ADD COLUMN password TEXT;')
|
||||
|
||||
def execute(self, command, args=(), save=False):
|
||||
''' Wrapper for executing SQL commands '''
|
||||
""" Wrapper for executing SQL commands """
|
||||
for tries in xrange(5, 0, -1):
|
||||
try:
|
||||
if args and isinstance(args, tuple):
|
||||
@@ -259,11 +259,11 @@ class HistoryDB(object):
|
||||
to_keep = int_conv(sabnzbd.cfg.history_retention())
|
||||
if to_keep > 0:
|
||||
logging.info('Removing all but last %s completed jobs from history', to_keep)
|
||||
return self.execute("""DELETE FROM history WHERE id NOT IN ( SELECT id FROM history WHERE status = 'Completed' ORDER BY completed DESC LIMIT ? )""", (to_keep,), save=True)
|
||||
return self.execute("""DELETE FROM history WHERE status = ? AND id NOT IN ( SELECT id FROM history WHERE status = ? ORDER BY completed DESC LIMIT ? )""", (Status.COMPLETED, Status.COMPLETED, to_keep), save=True)
|
||||
|
||||
def add_history_db(self, nzo, storage, path, postproc_time, script_output, script_line):
|
||||
""" Add a new job entry to the database """
|
||||
t = build_history_info(nzo, storage, path, postproc_time, script_output, script_line)
|
||||
t = build_history_info(nzo, storage, path, postproc_time, script_output, script_line, series_info=True)
|
||||
|
||||
self.execute("""INSERT INTO history (completed, name, nzb_name, category, pp, script, report,
|
||||
url, status, nzo_id, storage, path, script_log, script_line, download_time, postproc_time, stage_log,
|
||||
@@ -314,12 +314,11 @@ class HistoryDB(object):
|
||||
# Stage Name is separated by ::: stage lines by ; and stages by \r\n
|
||||
items = [unpack_history_info(item) for item in items]
|
||||
|
||||
return (items, fetched_items, total_items)
|
||||
return items, fetched_items, total_items
|
||||
|
||||
def have_episode(self, series, season, episode):
|
||||
""" Check whether History contains this series episode """
|
||||
total = 0
|
||||
series = series.lower().replace('.', ' ').replace('_', ' ').replace(' ', ' ')
|
||||
if series and season and episode:
|
||||
pattern = '%s/%s/%s' % (series, season, episode)
|
||||
res = self.execute("select count(*) from History WHERE series = ? AND STATUS != 'Failed'", (pattern,))
|
||||
@@ -330,10 +329,11 @@ class HistoryDB(object):
|
||||
pass
|
||||
return total > 0
|
||||
|
||||
def have_md5sum(self, md5sum):
|
||||
""" Check whether this md5sum already in History """
|
||||
def have_name_or_md5sum(self, name, md5sum):
|
||||
""" Check whether this name or md5sum is already in History """
|
||||
total = 0
|
||||
res = self.execute("select count(*) from History WHERE md5sum = ? AND STATUS != 'Failed'", (md5sum,))
|
||||
# Do the check case-insensitive
|
||||
res = self.execute("SELECT count(*) FROM History WHERE ( LOWER(name) = LOWER(?) OR md5sum = ? ) AND STATUS != 'Failed'", (name, md5sum))
|
||||
if res:
|
||||
try:
|
||||
total = self.c.fetchone().get('count(*)')
|
||||
@@ -375,7 +375,7 @@ class HistoryDB(object):
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
return (total, month, week)
|
||||
return total, month, week
|
||||
|
||||
def get_script_log(self, nzo_id):
|
||||
""" Return decompressed log file """
|
||||
@@ -400,7 +400,7 @@ class HistoryDB(object):
|
||||
return name
|
||||
|
||||
def get_path(self, nzo_id):
|
||||
""" Return the `incomplete` path of the job `nzo_id` """
|
||||
""" Return the `incomplete` path of the job `nzo_id` if it is still there """
|
||||
t = (nzo_id,)
|
||||
path = ''
|
||||
if self.execute('SELECT path FROM history WHERE nzo_id=?', t):
|
||||
@@ -408,7 +408,9 @@ class HistoryDB(object):
|
||||
path = self.c.fetchone().get('path')
|
||||
except AttributeError:
|
||||
pass
|
||||
return path
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
return None
|
||||
|
||||
def get_other(self, nzo_id):
|
||||
""" Return additional data for job `nzo_id` """
|
||||
@@ -421,9 +423,10 @@ class HistoryDB(object):
|
||||
pp = items.get('pp')
|
||||
script = items.get('script')
|
||||
cat = items.get('category')
|
||||
return dtype, url, pp, script, cat
|
||||
except (AttributeError, IndexError):
|
||||
return '', '', '', '', ''
|
||||
return dtype, url, pp, script, cat
|
||||
pass
|
||||
return '', '', '', '', ''
|
||||
|
||||
|
||||
def dict_factory(cursor, row):
|
||||
@@ -435,7 +438,7 @@ def dict_factory(cursor, row):
|
||||
|
||||
|
||||
_PP_LOOKUP = {0: '', 1: 'R', 2: 'U', 3: 'D'}
|
||||
def build_history_info(nzo, storage='', downpath='', postproc_time=0, script_output='', script_line=''):
|
||||
def build_history_info(nzo, storage='', downpath='', postproc_time=0, script_output='', script_line='', series_info=False):
|
||||
""" Collects all the information needed for the database """
|
||||
|
||||
if not downpath:
|
||||
@@ -488,7 +491,7 @@ def build_history_info(nzo, storage='', downpath='', postproc_time=0, script_out
|
||||
|
||||
# Analyze series info only when job is finished
|
||||
series = u''
|
||||
if postproc_time:
|
||||
if series_info:
|
||||
seriesname, season, episode, dummy = sabnzbd.newsunpack.analyse_show(nzo.final_name)
|
||||
if seriesname and season and episode:
|
||||
series = u'%s/%s/%s' % (seriesname.lower(), season, episode)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -125,7 +125,7 @@ class Decoder(Thread):
|
||||
nzf.article_count += 1
|
||||
found = True
|
||||
|
||||
except IOError, e:
|
||||
except IOError:
|
||||
logme = T('Decoding %s failed') % art_id
|
||||
logging.warning(logme)
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
@@ -134,7 +134,7 @@ class Decoder(Thread):
|
||||
sabnzbd.nzbqueue.NzbQueue.do.reset_try_lists(article)
|
||||
register = False
|
||||
|
||||
except MemoryError, e:
|
||||
except MemoryError:
|
||||
logme = T('Decoder failure: Out of memory')
|
||||
logging.warning(logme)
|
||||
anfo = sabnzbd.articlecache.ArticleCache.do.cache_info()
|
||||
@@ -175,7 +175,8 @@ class Decoder(Thread):
|
||||
if nzo.precheck:
|
||||
if found and not killed:
|
||||
# Pre-check, proper article found, just register
|
||||
logging.debug('Server %s has article %s', article.fetcher, art_id)
|
||||
if sabnzbd.LOG_ALL:
|
||||
logging.debug('Server %s has article %s', article.fetcher, art_id)
|
||||
register = True
|
||||
elif not killed and not found:
|
||||
logme = T('Badly formed yEnc article in %s') % art_id
|
||||
@@ -240,7 +241,6 @@ class Decoder(Thread):
|
||||
nzf = article.nzf
|
||||
yenc, data = yCheck(data)
|
||||
ybegin, ypart, yend = yenc
|
||||
decoded_data = None
|
||||
|
||||
# Deal with non-yencoded posts
|
||||
if not ybegin:
|
||||
@@ -379,7 +379,7 @@ def yCheck(data):
|
||||
except IndexError:
|
||||
break
|
||||
|
||||
return ((ybegin, ypart, yend), data)
|
||||
return (ybegin, ypart, yend), data
|
||||
|
||||
# Example: =ybegin part=1 line=128 size=123 name=-=DUMMY=- abc.par
|
||||
YSPLIT_RE = re.compile(r'([a-zA-Z0-9]+)=')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -28,9 +28,10 @@ import logging
|
||||
|
||||
import sabnzbd
|
||||
import sabnzbd.cfg as cfg
|
||||
from sabnzbd.misc import int_conv, clip_path, long_path, remove_all, globber, \
|
||||
format_time_string, has_win_device, real_path, remove_file
|
||||
from sabnzbd.misc import int_conv, clip_path, long_path, remove_all, \
|
||||
format_time_string, real_path, remove_file
|
||||
from sabnzbd.encoding import TRANS, unicoder
|
||||
from sabnzbd.decorators import synchronized
|
||||
from sabnzbd.newsunpack import build_command, EXTRACTFROM_RE, EXTRACTED_RE, rar_volumelist
|
||||
from sabnzbd.postproc import prepare_extraction_path
|
||||
from sabnzbd.utils.rarfile import RarFile
|
||||
@@ -46,7 +47,10 @@ if sabnzbd.WIN32:
|
||||
# Load the regular POpen (which is now patched on Windows)
|
||||
from subprocess import Popen
|
||||
|
||||
MAX_ACTIVE_UNPACKERS = 10
|
||||
# Need a lock to make sure start and stop is handled correctlty
|
||||
# Otherwise we could stop while the thread was still starting
|
||||
START_STOP_LOCK = threading.RLock()
|
||||
|
||||
ACTIVE_UNPACKERS = []
|
||||
|
||||
RAR_NR = re.compile(r'(.*?)(\.part(\d*).rar|\.r(\d*))$', re.IGNORECASE)
|
||||
@@ -72,6 +76,8 @@ class DirectUnpacker(threading.Thread):
|
||||
self.success_sets = {}
|
||||
self.next_sets = []
|
||||
|
||||
self.duplicate_lines = 0
|
||||
|
||||
nzo.direct_unpacker = self
|
||||
|
||||
def stop(self):
|
||||
@@ -110,6 +116,7 @@ class DirectUnpacker(threading.Thread):
|
||||
if none_counter > found_counter:
|
||||
self.total_volumes = {}
|
||||
|
||||
@synchronized(START_STOP_LOCK)
|
||||
def add(self, nzf):
|
||||
""" Add jobs and start instance of DirectUnpack """
|
||||
if not cfg.direct_unpack_tested():
|
||||
@@ -170,11 +177,11 @@ class DirectUnpacker(threading.Thread):
|
||||
break
|
||||
|
||||
# Error? Let PP-handle it
|
||||
if linebuf.endswith(('ERROR: ', 'Cannot create', 'in the encrypted file', 'CRC failed', \
|
||||
'checksum failed', 'You need to start extraction from a previous volume', \
|
||||
'password is incorrect', 'Write error', 'checksum error', \
|
||||
'start extraction from a previous volume')):
|
||||
logging.info('Error in DirectUnpack of %s', self.cur_setname)
|
||||
if linebuf.endswith(('ERROR: ', 'Cannot create', 'in the encrypted file', 'CRC failed', 'checksum failed',
|
||||
'You need to start extraction from a previous volume', 'password is incorrect',
|
||||
'Write error', 'checksum error', 'start extraction from a previous volume'
|
||||
'Unexpected end of archive')):
|
||||
logging.info('Error in DirectUnpack of %s: %s', self.cur_setname, linebuf.strip())
|
||||
self.abort()
|
||||
|
||||
if linebuf.endswith('\n'):
|
||||
@@ -265,13 +272,16 @@ class DirectUnpacker(threading.Thread):
|
||||
logging.info('DirectUnpacked volume %s for %s', self.cur_volume, self.cur_setname)
|
||||
|
||||
# If lines did not change and we don't have the next volume, this download is missing files!
|
||||
# In rare occasions we can get stuck forever with repeating lines
|
||||
if last_volume_linebuf == linebuf:
|
||||
if not self.have_next_volume():
|
||||
if not self.have_next_volume() or self.duplicate_lines > 10:
|
||||
logging.info('DirectUnpack failed due to missing files %s', self.cur_setname)
|
||||
self.abort()
|
||||
else:
|
||||
logging.debug('Duplicate output line detected: "%s"', last_volume_linebuf)
|
||||
|
||||
self.duplicate_lines += 1
|
||||
else:
|
||||
self.duplicate_lines = 0
|
||||
last_volume_linebuf = linebuf
|
||||
|
||||
# Show the log
|
||||
@@ -309,6 +319,7 @@ class DirectUnpacker(threading.Thread):
|
||||
with self.next_file_lock:
|
||||
self.next_file_lock.wait()
|
||||
|
||||
@synchronized(START_STOP_LOCK)
|
||||
def create_unrar_instance(self):
|
||||
""" Start the unrar instance using the user's options """
|
||||
# Generate extraction path and save for post-proc
|
||||
@@ -337,6 +348,11 @@ class DirectUnpacker(threading.Thread):
|
||||
# The first NZF
|
||||
self.rarfile_nzf = self.have_next_volume()
|
||||
|
||||
# Ignore if maybe this set is not there any more
|
||||
# This can happen due to race/timing issues when creating the sets
|
||||
if not self.rarfile_nzf:
|
||||
return
|
||||
|
||||
# Generate command
|
||||
rarfile_path = os.path.join(self.nzo.downpath, self.rarfile_nzf.filename)
|
||||
if sabnzbd.WIN32:
|
||||
@@ -366,9 +382,10 @@ class DirectUnpacker(threading.Thread):
|
||||
# Doing the first
|
||||
logging.info('DirectUnpacked volume %s for %s', self.cur_volume, self.cur_setname)
|
||||
|
||||
@synchronized(START_STOP_LOCK)
|
||||
def abort(self):
|
||||
""" Abort running instance and delete generated files """
|
||||
if not self.killed:
|
||||
if not self.killed and self.cur_setname:
|
||||
logging.info('Aborting DirectUnpack for %s', self.cur_setname)
|
||||
self.killed = True
|
||||
|
||||
@@ -377,9 +394,20 @@ class DirectUnpacker(threading.Thread):
|
||||
|
||||
# Abort Unrar
|
||||
if self.active_instance:
|
||||
self.active_instance.kill()
|
||||
# We need to wait for it to kill the process
|
||||
self.active_instance.wait()
|
||||
# First we try to abort gracefully
|
||||
try:
|
||||
self.active_instance.stdin.write('Q\n')
|
||||
time.sleep(0.2)
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
# Now force kill and give it a bit of time
|
||||
try:
|
||||
self.active_instance.kill()
|
||||
time.sleep(0.2)
|
||||
except AttributeError:
|
||||
# Already killed by the Quit command
|
||||
pass
|
||||
|
||||
# Wake up the thread
|
||||
with self.next_file_lock:
|
||||
@@ -404,7 +432,6 @@ class DirectUnpacker(threading.Thread):
|
||||
except:
|
||||
# The user will have to remove it themselves
|
||||
logging.info('Failed to clean Direct Unpack after aborting %s', rarfile_nzf.filename, exc_info=True)
|
||||
pass
|
||||
else:
|
||||
# We can just remove the whole path
|
||||
remove_all(extraction_path, recursive=True)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -76,7 +76,7 @@ def is_archive(path):
|
||||
except:
|
||||
logging.info(T('Cannot read %s'), path, exc_info=True)
|
||||
return -1, None, ''
|
||||
elif rarfile.is_rarfile(path):
|
||||
elif misc.is_rarfile(path):
|
||||
try:
|
||||
# Set path to tool to open it
|
||||
rarfile.UNRAR_TOOL = sabnzbd.newsunpack.RAR_COMMAND
|
||||
@@ -144,7 +144,7 @@ def ProcessArchiveFile(filename, path, pp=None, script=None, cat=None, catdir=No
|
||||
priority=priority, nzbname=nzbname)
|
||||
if not nzo.password:
|
||||
nzo.password = password
|
||||
except (TypeError, ValueError) as e:
|
||||
except (TypeError, ValueError):
|
||||
# Duplicate or empty, ignore
|
||||
pass
|
||||
except:
|
||||
@@ -232,7 +232,7 @@ def ProcessSingleFile(filename, path, pp=None, script=None, cat=None, catdir=Non
|
||||
# Empty, but correct file
|
||||
return -1, nzo_ids
|
||||
except:
|
||||
if data.find("<nzb") >= 0 and data.find("</nzb") < 0:
|
||||
if data.find("<nzb") >= 0 > data.find("</nzb"):
|
||||
# Looks like an incomplete file, retry
|
||||
return -2, nzo_ids
|
||||
else:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -305,13 +305,13 @@ class Downloader(Thread):
|
||||
self.force_disconnect = True
|
||||
|
||||
def limit_speed(self, value):
|
||||
''' Set the actual download speed in Bytes/sec
|
||||
""" Set the actual download speed in Bytes/sec
|
||||
When 'value' ends with a '%' sign or is within 1-100, it is interpreted as a pecentage of the maximum bandwidth
|
||||
When no '%' is found, it is interpreted as an absolute speed (including KMGT notation).
|
||||
'''
|
||||
"""
|
||||
if value:
|
||||
mx = cfg.bandwidth_max.get_int()
|
||||
if '%' in str(value) or (from_units(value) > 0 and from_units(value) < 101):
|
||||
if '%' in str(value) or (0 < from_units(value) < 101):
|
||||
limit = value.strip(' %')
|
||||
self.bandwidth_perc = from_units(limit)
|
||||
if mx:
|
||||
@@ -369,24 +369,24 @@ class Downloader(Thread):
|
||||
# Was it resolving problem?
|
||||
if server.info is False:
|
||||
# Warn about resolving issues
|
||||
errormsg = T('Cannot connect to server %s [%s]') % (server.id, T('Server name does not resolve'))
|
||||
errormsg = T('Cannot connect to server %s [%s]') % (server.host, T('Server name does not resolve'))
|
||||
if server.errormsg != errormsg:
|
||||
server.errormsg = errormsg
|
||||
logging.warning(errormsg)
|
||||
logging.warning(T('Server %s will be ignored for %s minutes'), server.id, _PENALTY_TIMEOUT)
|
||||
logging.warning(T('Server %s will be ignored for %s minutes'), server.host, _PENALTY_TIMEOUT)
|
||||
|
||||
# Not fully the same as the code below for optional servers
|
||||
server.bad_cons = 0
|
||||
server.active = False
|
||||
self.plan_server(server.id, _PENALTY_TIMEOUT)
|
||||
self.plan_server(server, _PENALTY_TIMEOUT)
|
||||
|
||||
# Optional and active server had too many problems.
|
||||
# Disable it now and send a re-enable plan to the scheduler
|
||||
if server.optional and server.active and (server.bad_cons / server.threads) > 3:
|
||||
server.bad_cons = 0
|
||||
server.active = False
|
||||
logging.warning(T('Server %s will be ignored for %s minutes'), server.id, _PENALTY_TIMEOUT)
|
||||
self.plan_server(server.id, _PENALTY_TIMEOUT)
|
||||
logging.warning(T('Server %s will be ignored for %s minutes'), server.host, _PENALTY_TIMEOUT)
|
||||
self.plan_server(server, _PENALTY_TIMEOUT)
|
||||
|
||||
# Remove all connections to server
|
||||
for nw in server.idle_threads + server.busy_threads:
|
||||
@@ -472,7 +472,7 @@ class Downloader(Thread):
|
||||
|
||||
if server.retention and article.nzf.nzo.avg_stamp < time.time() - server.retention:
|
||||
# Let's get rid of all the articles for this server at once
|
||||
logging.info('Job %s too old for %s, moving on', article.nzf.nzo.work_name, server.id)
|
||||
logging.info('Job %s too old for %s, moving on', article.nzf.nzo.work_name, server.host)
|
||||
while article:
|
||||
self.decode(article, None, None)
|
||||
article = article.nzf.nzo.get_article(server, self.servers)
|
||||
@@ -487,10 +487,10 @@ class Downloader(Thread):
|
||||
self.__request_article(nw)
|
||||
else:
|
||||
try:
|
||||
logging.info("%s@%s: Initiating connection", nw.thrdnum, server.id)
|
||||
logging.info("%s@%s: Initiating connection", nw.thrdnum, server.host)
|
||||
nw.init_connect(self.write_fds)
|
||||
except:
|
||||
logging.error(T('Failed to initialize %s@%s with reason: %s'), nw.thrdnum, server.id, sys.exc_info()[1])
|
||||
logging.error(T('Failed to initialize %s@%s with reason: %s'), nw.thrdnum, server.host, sys.exc_info()[1])
|
||||
self.__reset_nw(nw, "failed to initialize")
|
||||
|
||||
# Exit-point
|
||||
@@ -619,7 +619,7 @@ class Downloader(Thread):
|
||||
try:
|
||||
nw.finish_connect(nw.status_code)
|
||||
if sabnzbd.LOG_ALL:
|
||||
logging.debug("%s@%s last message -> %s", nw.thrdnum, nw.server.id, nntp_to_msg(nw.data))
|
||||
logging.debug("%s@%s last message -> %s", nw.thrdnum, nw.server.host, nntp_to_msg(nw.data))
|
||||
nw.clear_data()
|
||||
except NNTPPermanentError, error:
|
||||
# Handle login problems
|
||||
@@ -636,9 +636,9 @@ class Downloader(Thread):
|
||||
errormsg = T('Too many connections to server %s') % display_msg
|
||||
if server.errormsg != errormsg:
|
||||
server.errormsg = errormsg
|
||||
logging.warning(T('Too many connections to server %s'), server.id)
|
||||
logging.warning(T('Too many connections to server %s'), server.host)
|
||||
self.__reset_nw(nw, None, warn=False, destroy=True, quit=True)
|
||||
self.plan_server(server.id, _PENALTY_TOOMANY)
|
||||
self.plan_server(server, _PENALTY_TOOMANY)
|
||||
server.threads -= 1
|
||||
elif ecode in ('502', '481', '482') and clues_too_many_ip(msg):
|
||||
# Account sharing?
|
||||
@@ -646,7 +646,7 @@ class Downloader(Thread):
|
||||
errormsg = T('Probable account sharing') + display_msg
|
||||
if server.errormsg != errormsg:
|
||||
server.errormsg = errormsg
|
||||
name = ' (%s)' % server.id
|
||||
name = ' (%s)' % server.host
|
||||
logging.warning(T('Probable account sharing') + name)
|
||||
penalty = _PENALTY_SHARE
|
||||
block = True
|
||||
@@ -656,7 +656,7 @@ class Downloader(Thread):
|
||||
errormsg = T('Failed login for server %s') % display_msg
|
||||
if server.errormsg != errormsg:
|
||||
server.errormsg = errormsg
|
||||
logging.error(T('Failed login for server %s'), server.id)
|
||||
logging.error(T('Failed login for server %s'), server.host)
|
||||
penalty = _PENALTY_PERM
|
||||
block = True
|
||||
elif ecode in ('502', '482'):
|
||||
@@ -665,7 +665,7 @@ class Downloader(Thread):
|
||||
errormsg = T('Cannot connect to server %s [%s]') % ('', display_msg)
|
||||
if server.errormsg != errormsg:
|
||||
server.errormsg = errormsg
|
||||
logging.warning(T('Cannot connect to server %s [%s]'), server.id, msg)
|
||||
logging.warning(T('Cannot connect to server %s [%s]'), server.host, msg)
|
||||
if clues_pay(msg):
|
||||
penalty = _PENALTY_PERM
|
||||
else:
|
||||
@@ -674,7 +674,7 @@ class Downloader(Thread):
|
||||
elif ecode == '400':
|
||||
# Temp connection problem?
|
||||
if server.active:
|
||||
logging.debug('Unspecified error 400 from server %s', server.id)
|
||||
logging.debug('Unspecified error 400 from server %s', server.host)
|
||||
penalty = _PENALTY_VERYSHORT
|
||||
block = True
|
||||
else:
|
||||
@@ -683,25 +683,25 @@ class Downloader(Thread):
|
||||
errormsg = T('Cannot connect to server %s [%s]') % ('', display_msg)
|
||||
if server.errormsg != errormsg:
|
||||
server.errormsg = errormsg
|
||||
logging.warning(T('Cannot connect to server %s [%s]'), server.id, msg)
|
||||
logging.warning(T('Cannot connect to server %s [%s]'), server.host, msg)
|
||||
penalty = _PENALTY_UNKNOWN
|
||||
block = True
|
||||
if block or (penalty and server.optional):
|
||||
if server.active:
|
||||
server.active = False
|
||||
if penalty and (block or server.optional):
|
||||
self.plan_server(server.id, penalty)
|
||||
self.plan_server(server, penalty)
|
||||
sabnzbd.nzbqueue.NzbQueue.do.reset_all_try_lists()
|
||||
self.__reset_nw(nw, None, warn=False, quit=True)
|
||||
continue
|
||||
except:
|
||||
logging.error(T('Connecting %s@%s failed, message=%s'),
|
||||
nw.thrdnum, nw.server.id, nntp_to_msg(nw.data))
|
||||
nw.thrdnum, nw.server.host, nntp_to_msg(nw.data))
|
||||
# No reset-warning needed, above logging is sufficient
|
||||
self.__reset_nw(nw, None, warn=False)
|
||||
|
||||
if nw.connected:
|
||||
logging.info("Connecting %s@%s finished", nw.thrdnum, nw.server.id)
|
||||
logging.info("Connecting %s@%s finished", nw.thrdnum, nw.server.host)
|
||||
self.__request_article(nw)
|
||||
|
||||
elif nw.status_code == '223':
|
||||
@@ -718,27 +718,27 @@ class Downloader(Thread):
|
||||
elif nw.status_code in ('411', '423', '430'):
|
||||
done = True
|
||||
logging.debug('Thread %s@%s: Article %s missing (error=%s)',
|
||||
nw.thrdnum, nw.server.id, article.article, nw.status_code)
|
||||
nw.thrdnum, nw.server.host, article.article, nw.status_code)
|
||||
nw.clear_data()
|
||||
|
||||
elif nw.status_code == '480':
|
||||
if server.active:
|
||||
server.active = False
|
||||
server.errormsg = T('Server %s requires user/password') % ''
|
||||
self.plan_server(server.id, 0)
|
||||
self.plan_server(server, 0)
|
||||
sabnzbd.nzbqueue.NzbQueue.do.reset_all_try_lists()
|
||||
msg = T('Server %s requires user/password') % nw.server.id
|
||||
msg = T('Server %s requires user/password') % nw.server.host
|
||||
self.__reset_nw(nw, msg, quit=True)
|
||||
|
||||
elif nw.status_code == '500':
|
||||
if nzo.precheck:
|
||||
# Assume "STAT" command is not supported
|
||||
server.have_stat = False
|
||||
logging.debug('Server %s does not support STAT', server.id)
|
||||
logging.debug('Server %s does not support STAT', server.host)
|
||||
else:
|
||||
# Assume "BODY" command is not supported
|
||||
server.have_body = False
|
||||
logging.debug('Server %s does not support BODY', server.id)
|
||||
logging.debug('Server %s does not support BODY', server.host)
|
||||
nw.clear_data()
|
||||
self.__request_article(nw)
|
||||
|
||||
@@ -746,7 +746,7 @@ class Downloader(Thread):
|
||||
server.bad_cons = 0 # Succesful data, clear "bad" counter
|
||||
server.errormsg = server.warning = ''
|
||||
if sabnzbd.LOG_ALL:
|
||||
logging.debug('Thread %s@%s: %s done', nw.thrdnum, server.id, article.article)
|
||||
logging.debug('Thread %s@%s: %s done', nw.thrdnum, server.host, article.article)
|
||||
self.decode(article, nw.lines, nw.data)
|
||||
|
||||
nw.soft_reset()
|
||||
@@ -778,9 +778,9 @@ class Downloader(Thread):
|
||||
|
||||
if warn and errormsg:
|
||||
server.warning = errormsg
|
||||
logging.info('Thread %s@%s: ' + errormsg, nw.thrdnum, server.id)
|
||||
logging.info('Thread %s@%s: ' + errormsg, nw.thrdnum, server.host)
|
||||
elif errormsg:
|
||||
logging.info('Thread %s@%s: ' + errormsg, nw.thrdnum, server.id)
|
||||
logging.info('Thread %s@%s: ' + errormsg, nw.thrdnum, server.host)
|
||||
|
||||
if nw in server.busy_threads:
|
||||
server.busy_threads.remove(nw)
|
||||
@@ -814,11 +814,11 @@ class Downloader(Thread):
|
||||
if nw.server.send_group and nzo.group != nw.group:
|
||||
group = nzo.group
|
||||
if sabnzbd.LOG_ALL:
|
||||
logging.debug('Thread %s@%s: GROUP <%s>', nw.thrdnum, nw.server.id, group)
|
||||
logging.debug('Thread %s@%s: GROUP <%s>', nw.thrdnum, nw.server.host, group)
|
||||
nw.send_group(group)
|
||||
else:
|
||||
if sabnzbd.LOG_ALL:
|
||||
logging.debug('Thread %s@%s: BODY %s', nw.thrdnum, nw.server.id, nw.article.article)
|
||||
logging.debug('Thread %s@%s: BODY %s', nw.thrdnum, nw.server.host, nw.article.article)
|
||||
nw.body(nzo.precheck)
|
||||
|
||||
fileno = nw.nntp.sock.fileno()
|
||||
@@ -840,24 +840,24 @@ class Downloader(Thread):
|
||||
# Each server has a dictionary entry, consisting of a list of timestamps.
|
||||
|
||||
@synchronized(TIMER_LOCK)
|
||||
def plan_server(self, server_id, interval):
|
||||
def plan_server(self, server, interval):
|
||||
""" Plan the restart of a server in 'interval' minutes """
|
||||
if cfg.no_penalties() and interval > _PENALTY_SHORT:
|
||||
# Overwrite in case of no_penalties
|
||||
interval = _PENALTY_SHORT
|
||||
|
||||
logging.debug('Set planned server resume %s in %s mins', server_id, interval)
|
||||
if server_id not in self._timers:
|
||||
self._timers[server_id] = []
|
||||
logging.debug('Set planned server resume %s in %s mins', server.host, interval)
|
||||
if server.id not in self._timers:
|
||||
self._timers[server.id] = []
|
||||
stamp = time.time() + 60.0 * interval
|
||||
self._timers[server_id].append(stamp)
|
||||
self._timers[server.id].append(stamp)
|
||||
if interval:
|
||||
sabnzbd.scheduler.plan_server(self.trigger_server, [server_id, stamp], interval)
|
||||
sabnzbd.scheduler.plan_server(self.trigger_server, [server.id, stamp], interval)
|
||||
|
||||
@synchronized(TIMER_LOCK)
|
||||
def trigger_server(self, server_id, timestamp):
|
||||
""" Called by scheduler, start server if timer still valid """
|
||||
logging.debug('Trigger planned server resume %s', server_id)
|
||||
logging.debug('Trigger planned server resume for server-id %s', server_id)
|
||||
if server_id in self._timers:
|
||||
if timestamp in self._timers[server_id]:
|
||||
del self._timers[server_id]
|
||||
@@ -874,7 +874,7 @@ class Downloader(Thread):
|
||||
# Activate server if it was inactive
|
||||
for server in self.servers:
|
||||
if server.id == server_id and not server.active:
|
||||
logging.debug('Unblock server %s', server_id)
|
||||
logging.debug('Unblock server %s', server.host)
|
||||
self.init_server(server_id, server_id)
|
||||
break
|
||||
|
||||
@@ -891,7 +891,7 @@ class Downloader(Thread):
|
||||
kicked = []
|
||||
for server_id in self._timers.keys():
|
||||
if not [stamp for stamp in self._timers[server_id] if stamp >= now]:
|
||||
logging.debug('Forcing re-evaluation of server %s', server_id)
|
||||
logging.debug('Forcing re-evaluation of server-id %s', server_id)
|
||||
del self._timers[server_id]
|
||||
self.init_server(server_id, server_id)
|
||||
kicked.append(server_id)
|
||||
@@ -899,11 +899,14 @@ class Downloader(Thread):
|
||||
for server in self.servers:
|
||||
if server.id not in self._timers:
|
||||
if server.id not in kicked and not server.active:
|
||||
logging.debug('Forcing activation of server %s', server.id)
|
||||
logging.debug('Forcing activation of server %s', server.host)
|
||||
self.init_server(server.id, server.id)
|
||||
|
||||
def update_server(self, oldserver, newserver):
|
||||
""" Update the server and make sure we trigger
|
||||
the update in the loop to do housekeeping """
|
||||
self.init_server(oldserver, newserver)
|
||||
self.wakeup()
|
||||
|
||||
@NzbQueueLocker
|
||||
def wakeup(self):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2007-2018 The SABnzbd-Team <team@sabnzbd.org>
|
||||
# Copyright 2007-2019 The SABnzbd-Team <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
|
||||
@@ -44,7 +44,6 @@ from sabnzbd.misc import real_path, to_units, from_units, time_format, \
|
||||
long_path, calc_age, same_file, probablyipv4, probablyipv6, \
|
||||
int_conv, globber, globber_full, remove_all, get_base_url
|
||||
from sabnzbd.newswrapper import GetServerParms
|
||||
from sabnzbd.rating import Rating
|
||||
from sabnzbd.bpsmeter import BPSMeter
|
||||
from sabnzbd.encoding import TRANS, xml_name, LatinFilter, unicoder, special_fixer, \
|
||||
platform_encode
|
||||
@@ -59,13 +58,13 @@ from sabnzbd.decoder import HAVE_YENC, SABYENC_ENABLED
|
||||
from sabnzbd.utils.diskspeed import diskspeedmeasure
|
||||
from sabnzbd.utils.getperformance import getpystone
|
||||
|
||||
from sabnzbd.constants import NORMAL_PRIORITY, MEBI, DEF_SKIN_COLORS, DEF_STDINTF, \
|
||||
from sabnzbd.constants import NORMAL_PRIORITY, MEBI, DEF_SKIN_COLORS, \
|
||||
DEF_STDCONFIG, DEF_MAIN_TMPL, DEFAULT_PRIORITY
|
||||
|
||||
from sabnzbd.lang import list_languages
|
||||
|
||||
from sabnzbd.api import list_scripts, list_cats, del_from_section, \
|
||||
api_handler, build_queue, remove_callable, rss_qstatus, build_status, \
|
||||
api_handler, build_queue, remove_callable, build_status, \
|
||||
retry_job, retry_all_jobs, build_header, build_history, del_job_files, \
|
||||
format_bytes, std_time, report, del_hist_job, Ttemplate, build_queue_header, \
|
||||
_api_test_email, _api_test_notif
|
||||
@@ -150,7 +149,7 @@ def check_access(access_type=4):
|
||||
|
||||
def check_hostname():
|
||||
""" Check if hostname is allowed, to mitigate DNS-rebinding attack.
|
||||
Similar to CVE-2018-5702, we need to add protection even
|
||||
Similar to CVE-2019-5702, we need to add protection even
|
||||
if only allowed to be accessed via localhost.
|
||||
"""
|
||||
# If login is enabled, no API-key can be deducted
|
||||
@@ -162,7 +161,7 @@ def check_hostname():
|
||||
if not host:
|
||||
return False
|
||||
|
||||
# Remove the port-part (like ':8080'), if it is there, always on the right hand side.
|
||||
# Remove the port-part (like ':8080'), if it is there, always on the right hand side.
|
||||
# Not to be confused with IPv6 colons (within square brackets)
|
||||
host = re.sub(':[0123456789]+$', '', host).lower()
|
||||
|
||||
@@ -174,6 +173,11 @@ def check_hostname():
|
||||
if host in cfg.host_whitelist():
|
||||
return True
|
||||
|
||||
# Fine if ends with ".local" or ".local.", aka mDNS name
|
||||
# See rfc6762 Multicast DNS
|
||||
if host.endswith(('.local', '.local.')):
|
||||
return True
|
||||
|
||||
# Ohoh, bad
|
||||
log_warning_and_ip(T('Refused connection with hostname "%s" from:') % host)
|
||||
return False
|
||||
@@ -232,8 +236,7 @@ def check_login():
|
||||
|
||||
|
||||
def get_users():
|
||||
users = {}
|
||||
users[cfg.username()] = cfg.password()
|
||||
users = {cfg.username(): cfg.password()}
|
||||
return users
|
||||
|
||||
|
||||
@@ -496,7 +499,7 @@ class MainPage(object):
|
||||
# No session key check, due to fixed URLs
|
||||
name = kwargs.get('name')
|
||||
if name:
|
||||
history_db = sabnzbd.connect_db()
|
||||
history_db = sabnzbd.get_db_connection()
|
||||
return ShowString(history_db.get_name(name), history_db.get_script_log(name))
|
||||
else:
|
||||
raise Raiser(self.__root)
|
||||
@@ -770,7 +773,7 @@ class NzoPage(object):
|
||||
|
||||
# /SABnzbd_nzo_xxxxx/files
|
||||
elif 'files' in args:
|
||||
info = self.nzo_files(info, pnfo_list, nzo_id)
|
||||
info = self.nzo_files(info, nzo_id)
|
||||
|
||||
# /SABnzbd_nzo_xxxxx/save
|
||||
elif 'save' in args:
|
||||
@@ -780,7 +783,7 @@ class NzoPage(object):
|
||||
# /SABnzbd_nzo_xxxxx/
|
||||
else:
|
||||
info = self.nzo_details(info, pnfo_list, nzo_id)
|
||||
info = self.nzo_files(info, pnfo_list, nzo_id)
|
||||
info = self.nzo_files(info, nzo_id)
|
||||
|
||||
template = Template(file=os.path.join(sabnzbd.WEB_DIR, 'nzo.tmpl'),
|
||||
filter=FILTER, searchList=[info], compilerSettings=DIRECTIVES)
|
||||
@@ -832,7 +835,7 @@ class NzoPage(object):
|
||||
|
||||
return info
|
||||
|
||||
def nzo_files(self, info, pnfo_list, nzo_id):
|
||||
def nzo_files(self, info, nzo_id):
|
||||
active = []
|
||||
nzo = NzbQueue.do.get_nzo(nzo_id)
|
||||
if nzo:
|
||||
@@ -1103,7 +1106,7 @@ class HistoryPage(object):
|
||||
|
||||
@secured_expose(check_session_key=True)
|
||||
def purge(self, **kwargs):
|
||||
history_db = sabnzbd.connect_db()
|
||||
history_db = sabnzbd.get_db_connection()
|
||||
history_db.remove_history()
|
||||
raise queueRaiser(self.__root, kwargs)
|
||||
|
||||
@@ -1130,7 +1133,7 @@ class HistoryPage(object):
|
||||
@secured_expose(check_session_key=True)
|
||||
def purge_failed(self, **kwargs):
|
||||
del_files = bool(int_conv(kwargs.get('del_files')))
|
||||
history_db = sabnzbd.connect_db()
|
||||
history_db = sabnzbd.get_db_connection()
|
||||
if del_files:
|
||||
del_job_files(history_db.get_failed_paths())
|
||||
history_db.remove_failed()
|
||||
@@ -1170,7 +1173,7 @@ class HistoryPage(object):
|
||||
# No session key check, due to fixed URLs
|
||||
name = kwargs.get('name')
|
||||
if name:
|
||||
history_db = sabnzbd.connect_db()
|
||||
history_db = sabnzbd.get_db_connection()
|
||||
return ShowString(history_db.get_name(name), history_db.get_script_log(name))
|
||||
else:
|
||||
raise Raiser(self.__root)
|
||||
@@ -1361,14 +1364,14 @@ class ConfigSwitches(object):
|
||||
|
||||
##############################################################################
|
||||
SPECIAL_BOOL_LIST = \
|
||||
('start_paused', 'no_penalties', 'ignore_wrong_unrar', 'overwrite_files', 'enable_par_cleanup',
|
||||
('start_paused', 'no_penalties', 'fast_fail', 'ignore_wrong_unrar', 'overwrite_files', 'enable_par_cleanup',
|
||||
'queue_complete_pers', 'api_warnings', 'ampm', 'enable_unrar', 'enable_unzip', 'enable_7zip',
|
||||
'enable_filejoin', 'enable_tsjoin', 'ignore_unrar_dates', 'debug_log_decoding',
|
||||
'multipar', 'osx_menu', 'osx_speed', 'win_menu', 'use_pickle', 'allow_incomplete_nzb',
|
||||
'rss_filenames', 'ipv6_hosting', 'keep_awake', 'empty_postproc', 'html_login', 'wait_for_dfolder',
|
||||
'max_art_opt', 'warn_empty_nzb', 'enable_bonjour', 'reject_duplicate_files', 'warn_dupl_jobs',
|
||||
'replace_illegal', 'backup_for_duplicates', 'disable_api_key', 'api_logging',
|
||||
'ignore_empty_files', 'x_frame_options'
|
||||
'ignore_empty_files', 'x_frame_options', 'require_modern_tls'
|
||||
)
|
||||
SPECIAL_VALUE_LIST = \
|
||||
('size_limit', 'folder_max_length', 'fsys_type', 'movie_rename_limit', 'nomedia_marker',
|
||||
@@ -1874,9 +1877,13 @@ class ConfigRss(object):
|
||||
|
||||
@secured_expose(check_session_key=True, check_configlock=True)
|
||||
def upd_rss_filter(self, **kwargs):
|
||||
""" Wrapper, so we can call from api.py """
|
||||
self.internal_upd_rss_filter(**kwargs)
|
||||
|
||||
def internal_upd_rss_filter(self, **kwargs):
|
||||
""" Save updated filter definition """
|
||||
try:
|
||||
cfg = config.get_rss()[kwargs.get('feed')]
|
||||
feed_cfg = config.get_rss()[kwargs.get('feed')]
|
||||
except KeyError:
|
||||
raise rssRaiser(self.__root, kwargs)
|
||||
|
||||
@@ -1890,14 +1897,14 @@ class ConfigRss(object):
|
||||
enabled = kwargs.get('enabled', '0')
|
||||
|
||||
if filt:
|
||||
cfg.filters.update(int(kwargs.get('index', 0)), (cat, pp, script, kwargs.get('filter_type'),
|
||||
feed_cfg.filters.update(int(kwargs.get('index', 0)), (cat, pp, script, kwargs.get('filter_type'),
|
||||
platform_encode(filt), prio, enabled))
|
||||
|
||||
# Move filter if requested
|
||||
index = int_conv(kwargs.get('index', ''))
|
||||
new_index = kwargs.get('new_index', '')
|
||||
if new_index and int_conv(new_index) != index:
|
||||
cfg.filters.move(int(index), int_conv(new_index))
|
||||
feed_cfg.filters.move(int(index), int_conv(new_index))
|
||||
|
||||
config.save_config()
|
||||
self.__evaluate = False
|
||||
@@ -1915,13 +1922,17 @@ class ConfigRss(object):
|
||||
|
||||
@secured_expose(check_session_key=True, check_configlock=True)
|
||||
def del_rss_filter(self, **kwargs):
|
||||
""" Wrapper, so we can call from api.py """
|
||||
self.internal_del_rss_filter(**kwargs)
|
||||
|
||||
def internal_del_rss_filter(self, **kwargs):
|
||||
""" Remove one RSS filter """
|
||||
try:
|
||||
cfg = config.get_rss()[kwargs.get('feed')]
|
||||
feed_cfg = config.get_rss()[kwargs.get('feed')]
|
||||
except KeyError:
|
||||
raise rssRaiser(self.__root, kwargs)
|
||||
|
||||
cfg.filters.delete(int(kwargs.get('index', 0)))
|
||||
feed_cfg.filters.delete(int(kwargs.get('index', 0)))
|
||||
config.save_config()
|
||||
self.__evaluate = False
|
||||
self.__show_eval_button = True
|
||||
@@ -2036,15 +2047,8 @@ class ConfigScheduling(object):
|
||||
@secured_expose(check_configlock=True)
|
||||
def index(self, **kwargs):
|
||||
def get_days():
|
||||
days = {}
|
||||
days["*"] = T('Daily')
|
||||
days["1"] = T('Monday')
|
||||
days["2"] = T('Tuesday')
|
||||
days["3"] = T('Wednesday')
|
||||
days["4"] = T('Thursday')
|
||||
days["5"] = T('Friday')
|
||||
days["6"] = T('Saturday')
|
||||
days["7"] = T('Sunday')
|
||||
days = {"*": T('Daily'), "1": T('Monday'), "2": T('Tuesday'), "3": T('Wednesday'), "4": T('Thursday'),
|
||||
"5": T('Friday'), "6": T('Saturday'), "7": T('Sunday')}
|
||||
return days
|
||||
|
||||
conf = build_header(sabnzbd.WEB_DIR_CONFIG)
|
||||
@@ -2073,7 +2077,7 @@ class ConfigScheduling(object):
|
||||
if '%' not in value and from_units(value) < 1.0:
|
||||
value = T('off') # : "Off" value for speedlimit in scheduler
|
||||
else:
|
||||
if '%' not in value and int_conv(value) > 1 and int_conv(value) < 101:
|
||||
if '%' not in value and 1 < int_conv(value) < 101:
|
||||
value += '%'
|
||||
value = value.upper()
|
||||
if action in actions:
|
||||
@@ -2128,7 +2132,6 @@ class ConfigScheduling(object):
|
||||
@secured_expose(check_session_key=True, check_configlock=True)
|
||||
def addSchedule(self, **kwargs):
|
||||
servers = config.get_servers()
|
||||
categories = list_cats(False)
|
||||
minute = kwargs.get('minute')
|
||||
hour = kwargs.get('hour')
|
||||
days_of_week = ''.join([str(x) for x in kwargs.get('daysofweek', '')])
|
||||
@@ -2527,6 +2530,7 @@ def GetRssLog(feed):
|
||||
# These fields could be empty
|
||||
job['cat'] = job.get('cat', '')
|
||||
job['size'] = job.get('size', '')
|
||||
job['infourl'] = job.get('infourl', '')
|
||||
|
||||
# Auto-fetched jobs didn't have these fields set
|
||||
if job.get('url'):
|
||||
@@ -2587,7 +2591,7 @@ def GetRssLog(feed):
|
||||
LIST_EMAIL = (
|
||||
'email_endjob', 'email_cats', 'email_full',
|
||||
'email_server', 'email_to', 'email_from',
|
||||
'email_account', 'email_pwd', 'email_dir', 'email_rss'
|
||||
'email_account', 'email_pwd', 'email_rss'
|
||||
)
|
||||
LIST_GROWL = ('growl_enable', 'growl_cats', 'growl_server', 'growl_password',
|
||||
'growl_prio_startup', 'growl_prio_download', 'growl_prio_pp', 'growl_prio_complete', 'growl_prio_failed',
|
||||
@@ -2762,7 +2766,7 @@ def rss_history(url, limit=50, search=None):
|
||||
stageLine.append("<tr><dt>Stage %s</dt>" % stage['name'])
|
||||
actions = []
|
||||
for action in stage['actions']:
|
||||
actions.append("<dd>%s</dd>" % (action))
|
||||
actions.append("<dd>%s</dd>" % action)
|
||||
actions.sort()
|
||||
actions.reverse()
|
||||
for act in actions:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user