mirror of
https://github.com/sabnzbd/sabnzbd.git
synced 2026-01-05 14:09:22 -05:00
Compare commits
429 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6fd915365 | ||
|
|
fecae72267 | ||
|
|
7bffd91e3f | ||
|
|
f859521a7e | ||
|
|
a869386fac | ||
|
|
8bc7885b7a | ||
|
|
78be46738d | ||
|
|
6fce73855c | ||
|
|
5fa7bea885 | ||
|
|
62fb85a94b | ||
|
|
c840e3485e | ||
|
|
04c72d51fd | ||
|
|
eae1250cac | ||
|
|
634801431d | ||
|
|
e9a884ab39 | ||
|
|
40fc1511d0 | ||
|
|
8642723c77 | ||
|
|
15ac97e41a | ||
|
|
8202ae7cf6 | ||
|
|
1b459460dc | ||
|
|
bdf7df9ecd | ||
|
|
7e55c6a79d | ||
|
|
183570aaa5 | ||
|
|
de1d66d4dd | ||
|
|
0b27e57ad7 | ||
|
|
182bbd43c5 | ||
|
|
cdf4d6c5fd | ||
|
|
86db74c394 | ||
|
|
856e63794b | ||
|
|
c29a57445a | ||
|
|
4aba90ad3f | ||
|
|
4f2b6d4cd7 | ||
|
|
92067fa3f3 | ||
|
|
c26ea4ceeb | ||
|
|
35ccbff5b9 | ||
|
|
1a265a5176 | ||
|
|
ef2d243fa8 | ||
|
|
c2b8fa59a6 | ||
|
|
a85f9e39bd | ||
|
|
a13f8828fb | ||
|
|
7d391b8465 | ||
|
|
dbfa7cc4eb | ||
|
|
66e99df303 | ||
|
|
77ecf64443 | ||
|
|
f7060804b2 | ||
|
|
a44a1269c0 | ||
|
|
ac6fc37c7d | ||
|
|
9472d65af9 | ||
|
|
1b4c07f229 | ||
|
|
a645058ae1 | ||
|
|
edec6defbb | ||
|
|
27b3a3ddef | ||
|
|
da0903b8a6 | ||
|
|
a49a3b45e5 | ||
|
|
b9225fb153 | ||
|
|
656b7f0948 | ||
|
|
08b249ee09 | ||
|
|
5d76ebfe6e | ||
|
|
0d53b12ade | ||
|
|
f403e12a2a | ||
|
|
5abce26309 | ||
|
|
e73cb0958f | ||
|
|
70070e2f1c | ||
|
|
2685f9adab | ||
|
|
c43e74eabd | ||
|
|
b0d3306209 | ||
|
|
4aaabae109 | ||
|
|
b8188f999e | ||
|
|
4dc5ceb9b1 | ||
|
|
4f8e5053f7 | ||
|
|
3d97ce99e1 | ||
|
|
8620412b3a | ||
|
|
a6d07d89d0 | ||
|
|
a63efcefd6 | ||
|
|
bce9207161 | ||
|
|
12670dedbe | ||
|
|
40393f9548 | ||
|
|
94cae5f015 | ||
|
|
8353227f9d | ||
|
|
5c1d69b934 | ||
|
|
fb04b58b57 | ||
|
|
2bb14bba2a | ||
|
|
91195eb21b | ||
|
|
fa844a6223 | ||
|
|
906379dd09 | ||
|
|
37cded612f | ||
|
|
73e8fade61 | ||
|
|
3b8d6dd3c8 | ||
|
|
ff2ab2da8d | ||
|
|
85aed457b2 | ||
|
|
d624d1d5b6 | ||
|
|
758cc7afab | ||
|
|
d74b7b06d2 | ||
|
|
6c6a1049ea | ||
|
|
f380889d98 | ||
|
|
f61df0e126 | ||
|
|
ffca12123f | ||
|
|
1077ca3753 | ||
|
|
c7189dbceb | ||
|
|
f2361c49b4 | ||
|
|
f84cbb66c3 | ||
|
|
e45f254d19 | ||
|
|
b6cd3c0bae | ||
|
|
4a98724a35 | ||
|
|
4680fa5ae9 | ||
|
|
458f4e2bdc | ||
|
|
3357fd81c7 | ||
|
|
39009f2f71 | ||
|
|
9fdc1c6813 | ||
|
|
c5568fe830 | ||
|
|
3ebe277303 | ||
|
|
bad81f84b9 | ||
|
|
2ac08dd0e6 | ||
|
|
29c57dce0f | ||
|
|
27a9330638 | ||
|
|
4b42b1f55d | ||
|
|
db761395e5 | ||
|
|
249d73e270 | ||
|
|
408ffc4539 | ||
|
|
5d359afedb | ||
|
|
5e8e37e6a2 | ||
|
|
a74df6f04f | ||
|
|
10991d5472 | ||
|
|
b3206fe1db | ||
|
|
70391ea055 | ||
|
|
5b69155d49 | ||
|
|
941bb8adca | ||
|
|
b5eb014084 | ||
|
|
ee4b9339a7 | ||
|
|
3acfe19499 | ||
|
|
9bac23b38f | ||
|
|
b028258cbd | ||
|
|
4d442159cb | ||
|
|
181a91ccf6 | ||
|
|
1c6f2e9d10 | ||
|
|
244fe3b116 | ||
|
|
9ee7391918 | ||
|
|
2eadc3ace6 | ||
|
|
786b29c18d | ||
|
|
315f787d20 | ||
|
|
eb958327c5 | ||
|
|
e157d77a1e | ||
|
|
0347907044 | ||
|
|
e961c9ea8f | ||
|
|
f2ae281195 | ||
|
|
258c4f769d | ||
|
|
a4f76d59b0 | ||
|
|
52a3e04eae | ||
|
|
390abb00df | ||
|
|
02c50e4b17 | ||
|
|
8c8a78c0ab | ||
|
|
fb75cde710 | ||
|
|
b31fedd857 | ||
|
|
eafe69500b | ||
|
|
ae09990c43 | ||
|
|
fc855dccff | ||
|
|
cf54b65c32 | ||
|
|
3d57def676 | ||
|
|
74d2da8857 | ||
|
|
8cfd721ef6 | ||
|
|
d4e10f32e7 | ||
|
|
7974421fa1 | ||
|
|
5a7cff491d | ||
|
|
847a098d4e | ||
|
|
392ae695d0 | ||
|
|
b39effc067 | ||
|
|
908f4f01cf | ||
|
|
eb4de0ae0f | ||
|
|
8baab13192 | ||
|
|
abb38d3e49 | ||
|
|
d0016e390a | ||
|
|
c80012e367 | ||
|
|
19fc60a1d8 | ||
|
|
487c9e96ce | ||
|
|
cd337cb164 | ||
|
|
5c15747d62 | ||
|
|
7f11e6946b | ||
|
|
8fa77691d0 | ||
|
|
894e5910c3 | ||
|
|
54f33a72c4 | ||
|
|
566f90ff30 | ||
|
|
debc59744f | ||
|
|
33c6ac813c | ||
|
|
04875d07c5 | ||
|
|
39eb594e12 | ||
|
|
2561182126 | ||
|
|
a68ab27bac | ||
|
|
c27acb0e90 | ||
|
|
875d1ab952 | ||
|
|
3496480254 | ||
|
|
2ca79ab3b9 | ||
|
|
51ce7b657c | ||
|
|
67a34dcc78 | ||
|
|
81d27ece54 | ||
|
|
f3a2e54e61 | ||
|
|
1894ed72e3 | ||
|
|
64bf7d541e | ||
|
|
8beba13430 | ||
|
|
6379869d41 | ||
|
|
5a666a28ef | ||
|
|
3c80053010 | ||
|
|
7fd4941923 | ||
|
|
b42e600285 | ||
|
|
df8859d49e | ||
|
|
d62d006398 | ||
|
|
dadf1bdcc1 | ||
|
|
da961b7722 | ||
|
|
087326ed32 | ||
|
|
fc9f66e3e2 | ||
|
|
cb25e0dcb3 | ||
|
|
88da458c2b | ||
|
|
705b3aa74e | ||
|
|
f35bfa45db | ||
|
|
cc59037fbc | ||
|
|
1c442128dd | ||
|
|
d70d8d34dc | ||
|
|
2c972995d3 | ||
|
|
794f6239bb | ||
|
|
5f498c3bb1 | ||
|
|
8efce7430f | ||
|
|
fa3bf93464 | ||
|
|
ff1f0986cf | ||
|
|
a1601a0c1f | ||
|
|
2f457c2721 | ||
|
|
02c9d0d387 | ||
|
|
9b002fe568 | ||
|
|
73ec5df88d | ||
|
|
82e0635995 | ||
|
|
da0ff7be27 | ||
|
|
569260b396 | ||
|
|
bbce0afbf4 | ||
|
|
33022d82c4 | ||
|
|
a7c29fa317 | ||
|
|
8974944044 | ||
|
|
60c86a45da | ||
|
|
92883f313a | ||
|
|
ce4524e2bb | ||
|
|
fdf4242a6c | ||
|
|
e44c603ba7 | ||
|
|
1f30714e17 | ||
|
|
36f32f518f | ||
|
|
bdbd02fa0b | ||
|
|
0a1e018144 | ||
|
|
601649e028 | ||
|
|
7c17dc64c9 | ||
|
|
647f04b6f0 | ||
|
|
c2102c38f3 | ||
|
|
6c82e47d32 | ||
|
|
b53529614e | ||
|
|
2a25c201a7 | ||
|
|
8f3d5047fc | ||
|
|
6a08b5b71b | ||
|
|
c08715614a | ||
|
|
ea2b130b57 | ||
|
|
daa3b25822 | ||
|
|
0184e8de2f | ||
|
|
eec59252f6 | ||
|
|
2b7f8fb1c9 | ||
|
|
345a37d024 | ||
|
|
5f04211c58 | ||
|
|
80b679e9dc | ||
|
|
e9ecf39d54 | ||
|
|
c5a022958c | ||
|
|
97abbafbe9 | ||
|
|
776b0367a5 | ||
|
|
c6822fc4f5 | ||
|
|
a2f10b5416 | ||
|
|
4ea7ce7138 | ||
|
|
ab9842b599 | ||
|
|
7bba292f46 | ||
|
|
867bbd5326 | ||
|
|
2690f26300 | ||
|
|
b514c81015 | ||
|
|
cd75d5acd3 | ||
|
|
b9a60f598c | ||
|
|
7b39578461 | ||
|
|
8934c29617 | ||
|
|
dbaed5c8ed | ||
|
|
5a091d55a6 | ||
|
|
a28d7ecfab | ||
|
|
7dea433f52 | ||
|
|
80a2ffdead | ||
|
|
e4b5d937d7 | ||
|
|
5806f816b8 | ||
|
|
385928c6e5 | ||
|
|
3e1654356d | ||
|
|
def4d596dc | ||
|
|
a239039a89 | ||
|
|
1a71265354 | ||
|
|
9a3a3b0868 | ||
|
|
b0a109bd0d | ||
|
|
525d10c0ae | ||
|
|
8de65d48f3 | ||
|
|
a5f21c764c | ||
|
|
1e4e18e51d | ||
|
|
281921ec59 | ||
|
|
c10efcbf4c | ||
|
|
661ab24d6f | ||
|
|
4bf33f5a0a | ||
|
|
b256e086c7 | ||
|
|
a9470ae959 | ||
|
|
100018d6bf | ||
|
|
7719513c72 | ||
|
|
970703671d | ||
|
|
6d3a4a391c | ||
|
|
9838c6a05c | ||
|
|
5744b1ae98 | ||
|
|
879af8744d | ||
|
|
640f941180 | ||
|
|
a48d8b8f6a | ||
|
|
20d92bf36b | ||
|
|
7f2ab5d629 | ||
|
|
bb46b474c3 | ||
|
|
5a3e8836e0 | ||
|
|
e100c4ce7f | ||
|
|
32b3db80d8 | ||
|
|
7ac24e69c4 | ||
|
|
80f2a5476e | ||
|
|
d27237832e | ||
|
|
73a3ce9889 | ||
|
|
ff66b8ec01 | ||
|
|
d632084c58 | ||
|
|
4257ff3e67 | ||
|
|
72ca0a6ef7 | ||
|
|
5b361a6a2e | ||
|
|
40d3a69b1c | ||
|
|
0cc618e1b2 | ||
|
|
0ee04ada31 | ||
|
|
807b1c64dd | ||
|
|
690aad123c | ||
|
|
73b6a3159f | ||
|
|
73e8a18d5a | ||
|
|
e613dda536 | ||
|
|
2621b90d3b | ||
|
|
9e95736b48 | ||
|
|
de4ca8e55c | ||
|
|
f4247e0361 | ||
|
|
d9df7b66f5 | ||
|
|
c5feb5bdc9 | ||
|
|
ee170d2f51 | ||
|
|
eea6d07613 | ||
|
|
4a9a26d470 | ||
|
|
f949487a75 | ||
|
|
d7572c5772 | ||
|
|
74e3bbb83b | ||
|
|
adaa4cade5 | ||
|
|
09e670bce4 | ||
|
|
d6b601968d | ||
|
|
f07db641d4 | ||
|
|
1ffdd53629 | ||
|
|
97f91e734a | ||
|
|
4eee13ac02 | ||
|
|
5869022a28 | ||
|
|
19e77590f3 | ||
|
|
bc790275aa | ||
|
|
1c35cd9d65 | ||
|
|
d6dd8da81e | ||
|
|
d55b23c482 | ||
|
|
f95f83c85b | ||
|
|
f0fa67d16d | ||
|
|
89756b7c9e | ||
|
|
5f9693cb34 | ||
|
|
2856f3af8c | ||
|
|
e7b1db8b09 | ||
|
|
48c3a84b85 | ||
|
|
eca3705794 | ||
|
|
74fd17d7ac | ||
|
|
35cbf0ebb4 | ||
|
|
2eb8b8e2b2 | ||
|
|
883596d1d7 | ||
|
|
698487377b | ||
|
|
c3d826df8c | ||
|
|
d5536ed246 | ||
|
|
df077f8ef6 | ||
|
|
4293a098e3 | ||
|
|
cf07260186 | ||
|
|
9ad5bd477b | ||
|
|
1d2c1dbc6f | ||
|
|
8c44c5b79a | ||
|
|
0c84eb3dd0 | ||
|
|
869792c09e | ||
|
|
09ab158d66 | ||
|
|
f539a8ccda | ||
|
|
171f049607 | ||
|
|
43e47e6249 | ||
|
|
afbfe72489 | ||
|
|
59d042c9a7 | ||
|
|
38a613de45 | ||
|
|
1c27ebc1e4 | ||
|
|
6f1d8a99e7 | ||
|
|
8c9e5b4963 | ||
|
|
3c3aeac93c | ||
|
|
846c2761f6 | ||
|
|
d03eabe4d5 | ||
|
|
cad9be6e74 | ||
|
|
dbb166e94f | ||
|
|
6b92922ee5 | ||
|
|
479431b283 | ||
|
|
2ab1a27f8b | ||
|
|
8470e61e3f | ||
|
|
6c6c8c86d8 | ||
|
|
efab6ee229 | ||
|
|
72a1173615 | ||
|
|
1dfa3a64a7 | ||
|
|
7b36396570 | ||
|
|
c1a8470dcf | ||
|
|
ba0d9ac834 | ||
|
|
56d0feab12 | ||
|
|
0674737796 | ||
|
|
58b632b6c6 | ||
|
|
43f3e13491 | ||
|
|
7b69060776 | ||
|
|
75f6cc7f0f | ||
|
|
8ef8200363 | ||
|
|
8b31c38229 | ||
|
|
651591a063 | ||
|
|
c86b3c972b | ||
|
|
7529297151 | ||
|
|
2c411e343d | ||
|
|
e9d8f6aebd | ||
|
|
d144582f1c | ||
|
|
2d3e703979 | ||
|
|
af440ffffa | ||
|
|
e129b2df57 | ||
|
|
09f2b36920 | ||
|
|
37af295873 | ||
|
|
52d21e94d3 | ||
|
|
acd80cc05e | ||
|
|
de48464661 |
10
.github/dependabot.yml
vendored
10
.github/dependabot.yml
vendored
@@ -1,14 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "pip"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/builder"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/builder/osx"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
36
.github/renovate.json
vendored
Normal file
36
.github/renovate.json
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"$schema":"https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends":[
|
||||
"config:base",
|
||||
":disableDependencyDashboard"
|
||||
],
|
||||
"schedule":[
|
||||
"before 3am on Monday"
|
||||
],
|
||||
"ignorePaths":[
|
||||
"tests/**",
|
||||
".github/workflows/**"
|
||||
],
|
||||
"pip_requirements":{
|
||||
"fileMatch":[
|
||||
"requirements.txt",
|
||||
"builder/requirements.txt",
|
||||
"builder/osx/requirements.txt"
|
||||
]
|
||||
},
|
||||
"ignoreDeps":[
|
||||
"jaraco.text"
|
||||
],
|
||||
"packageRules":[
|
||||
{
|
||||
"matchPackagePatterns":[
|
||||
"*"
|
||||
],
|
||||
"groupName":"all dependencies",
|
||||
"groupSlug":"all",
|
||||
"automerge":true
|
||||
}
|
||||
],
|
||||
"automergeStrategy":"squash",
|
||||
"platformAutomerge":true
|
||||
}
|
||||
22
.github/workflows/black.yml
vendored
22
.github/workflows/black.yml
vendored
@@ -1,22 +0,0 @@
|
||||
name: Black Code Formatter
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
black:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Black Code Formatter
|
||||
uses: lgeiger/black-action@master
|
||||
with:
|
||||
args: >
|
||||
SABnzbd.py
|
||||
sabnzbd
|
||||
scripts
|
||||
tools
|
||||
builder
|
||||
tests
|
||||
--line-length=120
|
||||
--target-version=py37
|
||||
--check
|
||||
--diff
|
||||
129
.github/workflows/build_release.yml
vendored
129
.github/workflows/build_release.yml
vendored
@@ -2,52 +2,67 @@ name: Build binaries and source distribution
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
# Setting PYTHONNODEBUGRANGES reduces binary size
|
||||
env:
|
||||
AUTOMATION_GITHUB_TOKEN: ${{ secrets.AUTOMATION_GITHUB_TOKEN }}
|
||||
PYTHONNODEBUGRANGES: 1
|
||||
|
||||
jobs:
|
||||
build_windows:
|
||||
name: Build Windows binary
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 15
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.10 (64bit)
|
||||
uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.11 (64bit)
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.10"
|
||||
python-version: "3.11"
|
||||
architecture: "x64"
|
||||
- name: Cache Python virtualenv (64bit)
|
||||
uses: syphar/restore-virtualenv@v1.3
|
||||
id: cache-virtualenv-64bit
|
||||
with:
|
||||
custom_virtualenv_dir: "venv64"
|
||||
custom_cache_key_element: "release"
|
||||
requirement_files: |
|
||||
**/requirements.txt
|
||||
PKG-INFO
|
||||
- name: Install Python dependencies (64bit)
|
||||
if: steps.cache-virtualenv-64bit.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
python --version
|
||||
pip install --upgrade pip wheel
|
||||
pip install --upgrade -r requirements.txt
|
||||
pip install --upgrade -r builder/requirements.txt
|
||||
- name: Build source distribution
|
||||
run: python builder/package.py source
|
||||
- name: Upload source distribution
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
path: "*-src.tar.gz"
|
||||
name: Source distribution
|
||||
- name: Build Windows standalone binary and installer (64bit)
|
||||
run: python builder/package.py installer
|
||||
- name: Upload Windows standalone binary (64bit)
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: "*-win64-bin.zip"
|
||||
name: Windows Windows standalone binary (64bit)
|
||||
- name: Upload Windows installer (64bit)
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: "*-win-setup.exe"
|
||||
name: Windows installer
|
||||
- name: Set up Python 3.8 (32bit and legacy)
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.8"
|
||||
architecture: "x86"
|
||||
- name: Cache Python virtualenv (32bit and legacy)
|
||||
uses: syphar/restore-virtualenv@v1.3
|
||||
id: cache-virtualenv-32bit
|
||||
with:
|
||||
custom_virtualenv_dir: "venv32"
|
||||
custom_cache_key_element: "release"
|
||||
requirement_files: |
|
||||
**/requirements.txt
|
||||
PKG-INFO
|
||||
- name: Install Python dependencies (32bit and legacy)
|
||||
if: steps.cache-virtualenv-32bit.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
python --version
|
||||
pip install --upgrade pip wheel
|
||||
@@ -56,7 +71,7 @@ jobs:
|
||||
- name: Build Windows standalone binary (32bit and legacy)
|
||||
run: python builder/package.py binary
|
||||
- name: Upload Windows standalone binary (32bit and legacy)
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: "*-win32-bin.zip"
|
||||
name: Windows Windows standalone binary (32bit and legacy)
|
||||
@@ -67,65 +82,94 @@ jobs:
|
||||
build_macos:
|
||||
name: Build macOS binary
|
||||
runs-on: macos-11
|
||||
timeout-minutes: 15
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
SIGNING_AUTH: ${{ secrets.SIGNING_AUTH }}
|
||||
NOTARIZATION_USER: ${{ secrets.NOTARIZATION_USER }}
|
||||
NOTARIZATION_PASS: ${{ secrets.NOTARIZATION_PASS }}
|
||||
# We need the official Python, because the GA ones only support newer macOS versions
|
||||
# The deployment target is picked up by the Python build tools automatically
|
||||
# If updated, make sure to also set LSMinimumSystemVersion in SABnzbd.spec
|
||||
PYTHON_VERSION: "3.10.2"
|
||||
PYTHON_VERSION: "3.11.0"
|
||||
MACOSX_DEPLOYMENT_TARGET: "10.9"
|
||||
# We need to force compile for universal2 support
|
||||
CFLAGS: -arch arm64 -arch x86_64
|
||||
CFLAGS: -arch x86_64 -arch arm64
|
||||
ARCHFLAGS: -arch x86_64 -arch arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Cache Python download
|
||||
id: cache-python-download
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/python.pkg
|
||||
key: macOS-Python-${{ env.PYTHON_VERSION }}
|
||||
key: cache-macOS-Python-${{ env.PYTHON_VERSION }}
|
||||
- name: Get Python
|
||||
if: steps.cache-python-download.outputs.cache-hit != 'true'
|
||||
run: curl https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-macos11.pkg -o ~/python.pkg
|
||||
- name: Install Python
|
||||
run: sudo installer -pkg ~/python.pkg -target /
|
||||
run: |
|
||||
sudo installer -pkg ~/python.pkg -target /
|
||||
unlink /usr/local/bin/python
|
||||
ln -s /usr/local/bin/python3 /usr/local/bin/python
|
||||
- name: Cache Python virtualenv
|
||||
uses: syphar/restore-virtualenv@v1.3
|
||||
id: cache-virtualenv
|
||||
with:
|
||||
custom_cache_key_element: "release"
|
||||
requirement_files: |
|
||||
**/requirements.txt
|
||||
PKG-INFO
|
||||
- name: Install Python dependencies
|
||||
# We have to manually install a few packages:
|
||||
# 1. cffi will pick up the single-arch libffi from Homebrew, while Apple provides universal2-version
|
||||
# of libffi with XCode. So we forcefully have to remove the Homebrew one.
|
||||
# 2. Because building cryptography is hard, and we cannot force pip to fetch universal2 version we
|
||||
# We have to manually take a few steps:
|
||||
# 1. Because building cryptography is hard, and we cannot force pip to fetch universal2 version we
|
||||
# first install the x86 version (and it's dependencies) and then manually fetch the universal2 build
|
||||
# https://github.com/pyca/cryptography/issues/5918
|
||||
# 3. We need to build the PyInstaller bootloader from sources:
|
||||
# 2. We need to build the PyInstaller bootloader:
|
||||
# https://github.com/pyinstaller/pyinstaller/issues/6235
|
||||
# 3. TEMPORARY: Add aarch64 for orjson universal2 build, until they provide a wheel
|
||||
if: steps.cache-virtualenv.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
python3 --version
|
||||
pip3 install --upgrade pip wheel
|
||||
|
||||
brew uninstall libffi --ignore-dependencies
|
||||
ARCHFLAGS="-arch x86_64 -arch arm64" pip3 install --upgrade cffi --no-binary cffi
|
||||
pip3 install --upgrade -r requirements.txt --no-binary sabyenc3
|
||||
pip3 install --upgrade -r requirements.txt --no-binary cffi
|
||||
|
||||
pip3 uninstall cryptography -y
|
||||
pip3 download -r builder/osx/requirements.txt --platform macosx_10_10_universal2 --only-binary :all: --no-deps --dest .
|
||||
pip3 install -r builder/osx/requirements.txt --no-cache-dir --no-index --find-links .
|
||||
|
||||
rustup target add aarch64-apple-darwin
|
||||
|
||||
PYINSTALLER_COMPILE_BOOTLOADER=1 pip3 install --upgrade -r builder/requirements.txt --no-binary pyinstaller
|
||||
- name: Import macOS codesign certificates
|
||||
uses: apple-actions/import-codesign-certs@v1
|
||||
if: env.SIGNING_AUTH
|
||||
# Taken from https://github.com/Apple-Actions/import-codesign-certs/pull/27 (comments)
|
||||
env:
|
||||
CERTIFICATES_P12: ${{ secrets.CERTIFICATES_P12 }}
|
||||
CERTIFICATES_P12_PASSWORD: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
|
||||
MACOS_KEYCHAIN_TEMP_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_TEMP_PASSWORD }}
|
||||
run: |
|
||||
echo $CERTIFICATES_P12 | base64 --decode > certificate.p12
|
||||
security create-keychain -p "$MACOS_KEYCHAIN_TEMP_PASSWORD" build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p "$MACOS_KEYCHAIN_TEMP_PASSWORD" build.keychain
|
||||
security set-keychain-settings -lut 21600 build.keychain
|
||||
security import certificate.p12 -k build.keychain -P "$CERTIFICATES_P12_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign -T /usr/bin/xcrun
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_KEYCHAIN_TEMP_PASSWORD" build.keychain
|
||||
- name: Build source distribution
|
||||
# Run this on macOS so the line endings are correct by default
|
||||
run: python builder/package.py source
|
||||
- name: Upload source distribution
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
|
||||
p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
|
||||
path: "*-src.tar.gz"
|
||||
name: Source distribution
|
||||
- name: Build macOS binary
|
||||
env:
|
||||
SIGNING_AUTH: ${{ secrets.SIGNING_AUTH }}
|
||||
NOTARIZATION_USER: ${{ secrets.NOTARIZATION_USER }}
|
||||
NOTARIZATION_PASS: ${{ secrets.NOTARIZATION_PASS }}
|
||||
run: |
|
||||
python3 builder/package.py app
|
||||
python3 builder/make_dmg.py
|
||||
- name: Upload macOS binary
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: "*-osx.dmg"
|
||||
name: macOS binary (not notarized)
|
||||
@@ -138,15 +182,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
|
||||
env:
|
||||
SNAP_TOKEN: ${{ secrets.SNAP_TOKEN }}
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Release latest available Snap
|
||||
run: |
|
||||
sudo snap install snapcraft --classic
|
||||
echo "${SNAP_TOKEN}" | snapcraft login --with -
|
||||
python3 snap/local/release_snap.py
|
||||
|
||||
43
.github/workflows/integration_testing.yml
vendored
43
.github/workflows/integration_testing.yml
vendored
@@ -3,6 +3,27 @@ name: CI Tests
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
black:
|
||||
name: Black Code Formatter
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Black Code Formatter
|
||||
uses: lgeiger/black-action@master
|
||||
with:
|
||||
args: >
|
||||
SABnzbd.py
|
||||
sabnzbd
|
||||
scripts
|
||||
tools
|
||||
builder
|
||||
builder/SABnzbd.spec
|
||||
tests
|
||||
--line-length=120
|
||||
--target-version=py37
|
||||
--check
|
||||
--diff
|
||||
|
||||
test:
|
||||
name: Test ${{ matrix.name }} - Python ${{ matrix.python-version }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -10,27 +31,37 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.7", "3.8", "3.9", "3.10"]
|
||||
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
|
||||
os: [ubuntu-20.04]
|
||||
include:
|
||||
# TODO: Update to 3.10 when all packages are available, currently lxml is missing
|
||||
- name: macOS
|
||||
os: macos-latest
|
||||
python-version: "3.10"
|
||||
python-version: "3.11"
|
||||
- name: Windows
|
||||
os: windows-latest
|
||||
# lxml is not yet available for Python 3.11, so CI is stuck on 3.10 for now
|
||||
python-version: "3.10"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
architecture: "x64"
|
||||
- name: Install system dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt-get install unrar p7zip-full par2
|
||||
- name: Cache Python virtualenv
|
||||
uses: syphar/restore-virtualenv@v1.3
|
||||
id: cache-virtualenv
|
||||
with:
|
||||
custom_cache_key_element: "ci"
|
||||
requirement_files: |
|
||||
**/requirements.txt
|
||||
PKG-INFO
|
||||
- name: Install Python dependencies
|
||||
if: steps.cache-virtualenv.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
python --version
|
||||
pip install --upgrade pip wheel
|
||||
@@ -38,5 +69,3 @@ jobs:
|
||||
pip install --upgrade -r tests/requirements.txt
|
||||
- name: Test SABnzbd
|
||||
run: pytest -s
|
||||
|
||||
|
||||
|
||||
24
.github/workflows/translations.yml
vendored
24
.github/workflows/translations.yml
vendored
@@ -7,33 +7,35 @@ on:
|
||||
|
||||
jobs:
|
||||
translations:
|
||||
name: Update translatable texts
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TX_TOKEN: ${{ secrets.TX_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.AUTOMATION_GITHUB_TOKEN }}
|
||||
- name: Generate translatable texts
|
||||
run: |
|
||||
python3 tools/extract_pot.py
|
||||
- name: Install Transifex client
|
||||
if: env.TX_TOKEN
|
||||
# Sudo is needed to link the "tx"-command
|
||||
run: |
|
||||
sudo -H python3 -m pip install setuptools wheel
|
||||
sudo -H python3 -m pip install transifex-client
|
||||
- name: Push/pull Transifex translations
|
||||
if: env.TX_TOKEN
|
||||
run: |
|
||||
tx push --source --parallel
|
||||
tx pull --all --force --parallel
|
||||
curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash
|
||||
./tx push --source
|
||||
./tx pull --all --force
|
||||
- name: Compile translations to validate them
|
||||
run: |
|
||||
python3 tools/make_mo.py
|
||||
- name: Push translatable and translated texts back to repo
|
||||
uses: stefanzweifel/git-auto-commit-action@v4.5.1
|
||||
uses: stefanzweifel/git-auto-commit-action@v4.15.2
|
||||
if: env.TX_TOKEN
|
||||
with:
|
||||
commit_message: Update translatable texts
|
||||
commit_message: |
|
||||
Update translatable texts
|
||||
[skip ci]
|
||||
commit_user_name: SABnzbd Automation
|
||||
commit_user_email: bugs@sabnzbd.org
|
||||
commit_author: SABnzbd Automation <bugs@sabnzbd.org>
|
||||
file_pattern: "po/*.pot po/*.po"
|
||||
push_options: --force
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[sabnzbd-translations.po-main-sabnzbd-pot--develop]
|
||||
[o:sabnzbd:p:sabnzbd-translations:r:po-main-sabnzbd-pot--develop]
|
||||
file_filter = po/main/<lang>.po
|
||||
minimum_perc = 0
|
||||
source_file = po/main/SABnzbd.pot
|
||||
source_lang = en
|
||||
type = PO
|
||||
|
||||
[sabnzbd-translations.po-email-sabemail-pot--develop]
|
||||
[o:sabnzbd:p:sabnzbd-translations:r:po-email-sabemail-pot--develop]
|
||||
file_filter = po/email/<lang>.po
|
||||
minimum_perc = 0
|
||||
source_file = po/email/SABemail.pot
|
||||
source_lang = en
|
||||
type = PO
|
||||
|
||||
[sabnzbd-translations.po-nsis-sabnsis-pot--develop]
|
||||
[o:sabnzbd:p:sabnzbd-translations:r:po-nsis-sabnsis-pot--develop]
|
||||
file_filter = po/nsis/<lang>.po
|
||||
minimum_perc = 0
|
||||
source_file = po/nsis/SABnsis.pot
|
||||
|
||||
@@ -53,3 +53,6 @@
|
||||
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.
|
||||
|
||||
- If the queue is paused but one or more jobs have the Force priority, SABnzbd might still
|
||||
download some data from other jobs in the queue if active servers have unused connections.
|
||||
|
||||
4
PKG-INFO
4
PKG-INFO
@@ -1,7 +1,7 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: SABnzbd
|
||||
Version: 3.5.3
|
||||
Summary: SABnzbd-3.5.3
|
||||
Version: 3.7.0
|
||||
Summary: SABnzbd-3.7.0
|
||||
Home-page: https://sabnzbd.org
|
||||
Author: The SABnzbd Team
|
||||
Author-email: team@sabnzbd.org
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
SABnzbd - The automated Usenet download tool
|
||||
============================================
|
||||
|
||||

|
||||

|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
|
||||
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
|
||||
[](https://discord.gg/KQzDe7fvNU)
|
||||
|
||||
SABnzbd is an Open Source Binary Newsreader written in Python.
|
||||
|
||||
|
||||
74
README.mkd
74
README.mkd
@@ -1,49 +1,39 @@
|
||||
Release Notes - SABnzbd 3.5.3
|
||||
Release Notes - SABnzbd 3.7.0
|
||||
=========================================================
|
||||
|
||||
## Bugfix since 3.5.0
|
||||
- Prevent disk errors due to Direct Unpack being too aggressive.
|
||||
- URL's waiting to fetch get stuck indefinitely upon restart.
|
||||
## Changes since 3.6.1
|
||||
- The queue and history can be filtered using keywords:
|
||||
`cat` and `priority`. For example: `show name cat:tv`.
|
||||
- Use shortcut `shift + arrow-key` to navigate the queue/history pages.
|
||||
- The backup is now created in a local folder for security.
|
||||
- Recurring backups can be configured using the scheduler.
|
||||
- Improvements to Deobfuscate Final Filenames.
|
||||
- RSS overview shows the rule that accepted the job.
|
||||
- Added option to sort the queue by `% downloaded`.
|
||||
- Added option to replace underscores with dots in folder names.
|
||||
- SABnzbd Host input will be validated before being applied.
|
||||
- Moved system load information from the main page to the Status window.
|
||||
- Console logging is now written to `stdout` instead of `stderr`.
|
||||
- Removed Special settings `enable_meta`, `disable_key`,
|
||||
`replace_illegal`, `osx_speed` and `show_sysload`.
|
||||
- Merged Special settings `win_menu` and `osx_menu` into `tray_icon`.
|
||||
- macOS/Windows: Use Python 3.11, slightly boosting overall performance.
|
||||
- macOS/Windows: Updated UnRar to 6.12.
|
||||
- Windows: Updated MultiPar to 1.3.2.5.
|
||||
|
||||
## Changes and bugfixes since 3.5.0
|
||||
- Prevent permissions errors on systems that do not support them.
|
||||
- Small changes in file assembly and Direct Unpack processing.
|
||||
- Changes to the transition from download to active post-processing.
|
||||
- Malformed NZB files could result in a crash.
|
||||
- Prevent crash in Direct Unpack for obfuscated posts.
|
||||
- RSS feeds with HTML-characters in the name resulted in crashes.
|
||||
- macOS: failed to start on older macOS versions.
|
||||
# API changes since 3.6.1
|
||||
- Minor improvements in API performance.
|
||||
- Removed fields `scripts` and `categories` from `queue` API call.
|
||||
- Moved `loadavg` from `queue` to `status` API call.
|
||||
|
||||
## Changes since 3.4.2
|
||||
- Removed Python 3.6 support.
|
||||
- SOCKS5 proxy support for all outgoing connections.
|
||||
- Restored support for UUencoded jobs.
|
||||
- `Required` server option: in case of connection failures, the queue
|
||||
will be paused for a few minutes instead of skipping the server.
|
||||
- Added Special option to preserve paused state after a restart.
|
||||
- Show an estimated time-left indicator for repair and unpacking.
|
||||
- Require TLS version 1.2 or higher for SSL news server connections.
|
||||
- Setting custom ciphers forces the maximum TLS version to 1.2.
|
||||
- Reduced memory usage during and after parsing `.nzb` files.
|
||||
- Handle multiple passwords stored in NZB-file.
|
||||
- macOS/Linux: `Permissions` are only applied if any are set.
|
||||
- macOS/Windows: updated to Python 3.10.2.
|
||||
- macOS: run native on M1 systems. However, included tools
|
||||
(`par2`, `unrar` and `7za`) still require Rosetta emulation.
|
||||
- Snap: updated to `core20` base and restore 7zip support.
|
||||
|
||||
## Bugfixes since 3.4.2
|
||||
- Global interface settings would not always be applied correctly.
|
||||
- Email notification setting was not shown correctly.
|
||||
- Improvements and fixes for `Defobfuscate final filenames`.
|
||||
- `Post-Process Only Verified Jobs` would not always work as intended.
|
||||
- Correctly detect too little disk space when unpacking 7zip's.
|
||||
- Improvements to handling of repair by MultiPar and par2cmdline.
|
||||
- HTML characters in configuration fields were shown incorrectly.
|
||||
- On Retry the number of downloaded bytes could exceed the total bytes.
|
||||
- `unrar` logging of Direct Unpack was not logged if it was aborted.
|
||||
- Windows: `portable.cmd` was not included in the release.
|
||||
- Windows: print low-level Windows error on `IOError`.
|
||||
# Bugfixes since 3.6.1
|
||||
- Free Space Detection was too strict when using Direct Unpack.
|
||||
- File uploads with special characters would be parsed incorrectly.
|
||||
- Passwords from NZB meta-data were tried multiple times.
|
||||
- Passwords were not always supplied to the pre-queue script.
|
||||
- RSS-feed names were not sanitized when renamed.
|
||||
- Make sure short-dates are detected as `YY-MM-DD` in Sorting.
|
||||
- Show the custom job name in History when the NZB could not be fetched.
|
||||
|
||||
## Upgrade notices
|
||||
- The download statistics file `totals10.sab` is updated in 3.2.x
|
||||
|
||||
59
SABnzbd.py
59
SABnzbd.py
@@ -64,7 +64,7 @@ from sabnzbd.constants import (
|
||||
DEF_TIMEOUT,
|
||||
DEF_LOG_ERRFILE,
|
||||
DEF_MAIN_TMPL,
|
||||
DEF_STDINTF,
|
||||
DEF_STD_WEB_DIR,
|
||||
DEF_WORKDIR,
|
||||
DEF_INTERFACES,
|
||||
DEF_LANGUAGE,
|
||||
@@ -74,7 +74,7 @@ from sabnzbd.constants import (
|
||||
MAX_WARNINGS,
|
||||
RSS_FILE_NAME,
|
||||
DEF_LOG_FILE,
|
||||
DEF_STDCONFIG,
|
||||
DEF_STD_CONFIG,
|
||||
DEF_LOG_CHERRY,
|
||||
)
|
||||
import sabnzbd.newsunpack
|
||||
@@ -100,7 +100,7 @@ import sabnzbd.config as config
|
||||
import sabnzbd.cfg
|
||||
import sabnzbd.notifier as notifier
|
||||
import sabnzbd.zconfig
|
||||
from sabnzbd.getipaddress import localipv4, publicipv4, ipv6
|
||||
from sabnzbd.getipaddress import localipv4, publicipv4, ipv6, dnslookup
|
||||
from sabnzbd.utils.getperformance import getpystone, getcpu
|
||||
import sabnzbd.utils.ssdp as ssdp
|
||||
|
||||
@@ -326,7 +326,7 @@ def identify_web_template(key, defweb, wdir):
|
||||
|
||||
if not os.path.exists(full_main):
|
||||
helpful_warning(T("Cannot find web template: %s, trying standard template"), full_main)
|
||||
full_dir = real_path(sabnzbd.DIR_INTERFACES, DEF_STDINTF)
|
||||
full_dir = real_path(sabnzbd.DIR_INTERFACES, DEF_STD_WEB_DIR)
|
||||
full_main = real_path(full_dir, DEF_MAIN_TMPL)
|
||||
if not os.path.exists(full_main):
|
||||
logging.exception("Cannot find standard template: %s", full_dir)
|
||||
@@ -397,7 +397,7 @@ def get_user_profile_paths():
|
||||
sabnzbd.DIR_HOME = long_path(sabnzbd.DIR_HOME)
|
||||
return
|
||||
|
||||
elif sabnzbd.DARWIN:
|
||||
elif sabnzbd.MACOS:
|
||||
home = os.environ.get("HOME")
|
||||
if home:
|
||||
sabnzbd.DIR_LCLDATA = "%s/Library/Application Support/SABnzbd" % home
|
||||
@@ -421,6 +421,7 @@ def print_modules():
|
||||
if sabnzbd.decoder.SABYENC_ENABLED:
|
||||
# Yes, we have SABYenc, and it's the correct version, so it's enabled
|
||||
logging.info("SABYenc module (v%s)... found!", sabnzbd.decoder.SABYENC_VERSION)
|
||||
logging.info("SABYenc module is using SIMD set: %s", sabnzbd.decoder.SABYENC_SIMD)
|
||||
else:
|
||||
# Something wrong with SABYenc, so let's determine and print what:
|
||||
if sabnzbd.decoder.SABYENC_VERSION:
|
||||
@@ -458,7 +459,7 @@ def print_modules():
|
||||
have_str = "%.2f" % (float(sabnzbd.newsunpack.RAR_VERSION) / 100)
|
||||
want_str = "%.2f" % (float(sabnzbd.constants.REC_RAR_VERSION) / 100)
|
||||
helpful_warning(T("Your UNRAR version is %s, we recommend version %s or higher.<br />"), have_str, want_str)
|
||||
elif not (sabnzbd.WIN32 or sabnzbd.DARWIN):
|
||||
elif not (sabnzbd.WIN32 or sabnzbd.MACOS):
|
||||
logging.info("UNRAR binary version %.2f", (float(sabnzbd.newsunpack.RAR_VERSION) / 100))
|
||||
else:
|
||||
logging.error(T("unrar binary... NOT found"))
|
||||
@@ -468,7 +469,7 @@ def print_modules():
|
||||
# If available, we prefer 7zip over unzip
|
||||
if sabnzbd.newsunpack.SEVENZIP_COMMAND:
|
||||
logging.info("7za binary... found (%s)", sabnzbd.newsunpack.SEVENZIP_COMMAND)
|
||||
if not (sabnzbd.WIN32 or sabnzbd.DARWIN):
|
||||
if not (sabnzbd.WIN32 or sabnzbd.MACOS):
|
||||
logging.info("7za binary version %s", sabnzbd.newsunpack.SEVENZIP_VERSION)
|
||||
else:
|
||||
logging.info(T("7za binary... NOT found!"))
|
||||
@@ -616,7 +617,7 @@ def get_webhost(cherryhost, cherryport, https_port):
|
||||
browserhost = cherryhost
|
||||
|
||||
# Some systems don't like brackets in numerical ipv6
|
||||
if sabnzbd.DARWIN:
|
||||
if sabnzbd.MACOS:
|
||||
cherryhost = cherryhost.strip("[]")
|
||||
else:
|
||||
try:
|
||||
@@ -631,7 +632,7 @@ def get_webhost(cherryhost, cherryport, https_port):
|
||||
if ipv6 and ipv4 and cherryhost == "" and sabnzbd.WIN32:
|
||||
helpful_warning(T("Please be aware the 0.0.0.0 hostname will need an IPv6 address for external access"))
|
||||
|
||||
if cherryhost == "localhost" and not sabnzbd.WIN32 and not sabnzbd.DARWIN:
|
||||
if cherryhost == "localhost" and not sabnzbd.WIN32 and not sabnzbd.MACOS:
|
||||
# On the Ubuntu family, localhost leads to problems for CherryPy
|
||||
ips = ip_extract()
|
||||
if "127.0.0.1" in ips and "::1" in ips:
|
||||
@@ -640,7 +641,7 @@ def get_webhost(cherryhost, cherryport, https_port):
|
||||
browserhost = "127.0.0.1"
|
||||
|
||||
# This is to please Chrome on macOS
|
||||
if cherryhost == "localhost" and sabnzbd.DARWIN:
|
||||
if cherryhost == "localhost" and sabnzbd.MACOS:
|
||||
cherryhost = "127.0.0.1"
|
||||
browserhost = "localhost"
|
||||
|
||||
@@ -1155,7 +1156,7 @@ def main():
|
||||
daemonize()
|
||||
else:
|
||||
if console_logging:
|
||||
console = logging.StreamHandler()
|
||||
console = logging.StreamHandler(stream=sys.stdout)
|
||||
console.setLevel(LOGLEVELS[logging_level + 1])
|
||||
console.setFormatter(logging.Formatter(logformat))
|
||||
logger.addHandler(console)
|
||||
@@ -1192,7 +1193,7 @@ def main():
|
||||
logging.info("Preferred encoding = %s", sabnzbd.encoding.CODEPAGE)
|
||||
|
||||
# On Linux/FreeBSD/Unix "UTF-8" is strongly, strongly adviced:
|
||||
if not sabnzbd.WIN32 and not sabnzbd.DARWIN and not ("utf-8" in sabnzbd.encoding.CODEPAGE.lower()):
|
||||
if not sabnzbd.WIN32 and not sabnzbd.MACOS and not ("utf-8" in sabnzbd.encoding.CODEPAGE.lower()):
|
||||
helpful_warning(
|
||||
T(
|
||||
"SABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads."
|
||||
@@ -1207,6 +1208,9 @@ def main():
|
||||
sabnzbd.ORG_UMASK,
|
||||
)
|
||||
|
||||
# Log JSON module in case of problems
|
||||
logging.debug("JSON-module = %s %s", sabnzbd.api.json.__name__, sabnzbd.api.json.__version__)
|
||||
|
||||
# SSL Information
|
||||
logging.info("SSL version = %s", ssl.OPENSSL_VERSION)
|
||||
|
||||
@@ -1230,13 +1234,14 @@ def main():
|
||||
logging.debug("Available certificates = %s", repr(ssl.create_default_context().cert_store_stats()))
|
||||
|
||||
# List networking
|
||||
logging.debug("Local IPv4 address = %s", localipv4())
|
||||
logging.debug("Public IPv4 address = %s", publicipv4())
|
||||
logging.debug("IPv6 address = %s", ipv6())
|
||||
localipv4()
|
||||
publicipv4()
|
||||
ipv6()
|
||||
dnslookup()
|
||||
|
||||
# Measure and log system performance measured by pystone and - if possible - CPU model
|
||||
logging.debug("CPU Pystone available performance = %s", getpystone())
|
||||
logging.debug("CPU model = %s", getcpu())
|
||||
# Measure basic system performance measured by pystone and - if possible - CPU model
|
||||
getpystone()
|
||||
getcpu()
|
||||
|
||||
logging.info("Using INI file %s", inifile)
|
||||
|
||||
@@ -1247,15 +1252,15 @@ def main():
|
||||
|
||||
os.chdir(sabnzbd.DIR_PROG)
|
||||
|
||||
sabnzbd.WEB_DIR = identify_web_template(sabnzbd.cfg.web_dir, DEF_STDINTF, fix_webname(web_dir))
|
||||
sabnzbd.WEB_DIR_CONFIG = identify_web_template(None, DEF_STDCONFIG, "")
|
||||
sabnzbd.WEB_DIR = identify_web_template(sabnzbd.cfg.web_dir, DEF_STD_WEB_DIR, fix_webname(web_dir))
|
||||
sabnzbd.WEB_DIR_CONFIG = identify_web_template(None, DEF_STD_CONFIG, "")
|
||||
sabnzbd.WIZARD_DIR = os.path.join(sabnzbd.DIR_INTERFACES, "wizard")
|
||||
|
||||
sabnzbd.WEB_COLOR = check_template_scheme(sabnzbd.cfg.web_color(), sabnzbd.WEB_DIR)
|
||||
sabnzbd.cfg.web_color.set(sabnzbd.WEB_COLOR)
|
||||
|
||||
# Handle the several tray icons
|
||||
if sabnzbd.cfg.win_menu() and not sabnzbd.DAEMON and not sabnzbd.WIN_SERVICE:
|
||||
if sabnzbd.cfg.tray_icon() and not sabnzbd.DAEMON and not sabnzbd.WIN_SERVICE:
|
||||
if sabnzbd.WIN32:
|
||||
sabnzbd.WINTRAY = sabnzbd.sabtray.SABTrayThread()
|
||||
elif sabnzbd.LINUX_POWER and os.environ.get("DISPLAY"):
|
||||
@@ -1266,7 +1271,7 @@ def main():
|
||||
from gi.repository import Gtk
|
||||
import sabnzbd.sabtraylinux
|
||||
|
||||
sabnzbd.LINUXTRAY = sabnzbd.sabtraylinux.StatusIcon()
|
||||
sabnzbd.sabtraylinux.StatusIcon()
|
||||
except:
|
||||
logging.info("python3-gi not found, no SysTray.")
|
||||
|
||||
@@ -1582,9 +1587,13 @@ def main():
|
||||
sys.argv = sabnzbd.RESTART_ARGS
|
||||
os.chdir(org_dir)
|
||||
|
||||
# Restore backup
|
||||
if sabnzbd.RESTORE_DATA:
|
||||
config.restore_config_backup(sabnzbd.RESTORE_DATA)
|
||||
|
||||
# Binaries require special restart
|
||||
if hasattr(sys, "frozen"):
|
||||
if sabnzbd.DARWIN:
|
||||
if sabnzbd.MACOS:
|
||||
# On macOS restart of app instead of embedded python
|
||||
my_name = sabnzbd.MY_FULLNAME.replace("/Contents/MacOS/SABnzbd", "")
|
||||
my_args = " ".join(sys.argv[1:])
|
||||
@@ -1609,7 +1618,7 @@ def main():
|
||||
sys.stdout.flush()
|
||||
sabnzbd.pid_file()
|
||||
|
||||
if hasattr(sys, "frozen") and sabnzbd.DARWIN:
|
||||
if hasattr(sys, "frozen") and sabnzbd.MACOS:
|
||||
try:
|
||||
AppHelper.stopEventLoop()
|
||||
except:
|
||||
@@ -1747,7 +1756,7 @@ if __name__ == "__main__":
|
||||
if not handle_windows_service():
|
||||
main()
|
||||
|
||||
elif sabnzbd.DARWIN and sabnzbd.FOUNDATION:
|
||||
elif sabnzbd.MACOS and sabnzbd.FOUNDATION:
|
||||
# macOS binary runner
|
||||
from threading import Thread
|
||||
from PyObjCTools import AppHelper
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- mode: python -*-
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import pkginfo
|
||||
@@ -45,7 +46,7 @@ extra_hiddenimports.extend(collect_submodules("guessit.data"))
|
||||
|
||||
# Add platform specific stuff
|
||||
if sys.platform == "darwin":
|
||||
extra_hiddenimports.extend(["pyobjc", "objc", "PyObjCTools"])
|
||||
extra_hiddenimports.extend(["objc", "PyObjCTools"])
|
||||
# macOS folders
|
||||
extra_folders += ["osx/par2/", "osx/unrar/", "osx/7zip/"]
|
||||
# Add NZB-icon file
|
||||
@@ -121,11 +122,17 @@ pyi_analysis = Analysis(
|
||||
["SABnzbd.py"],
|
||||
datas=extra_pyinstaller_files,
|
||||
hiddenimports=extra_hiddenimports,
|
||||
excludes=["FixTk", "tcl", "tk", "_tkinter", "tkinter", "Tkinter"],
|
||||
excludes=["ujson", "FixTk", "tcl", "tk", "_tkinter", "tkinter", "Tkinter"],
|
||||
)
|
||||
|
||||
pyz = PYZ(pyi_analysis.pure, pyi_analysis.zipped_data)
|
||||
|
||||
codesign_identity = os.environ.get("SIGNING_AUTH")
|
||||
if not codesign_identity:
|
||||
# PyInstaller needs specifically None, not just an empty value
|
||||
codesign_identity = None
|
||||
|
||||
# macOS specific parameters are ignored on other platforms
|
||||
exe = EXE(
|
||||
pyz,
|
||||
pyi_analysis.scripts,
|
||||
@@ -138,6 +145,8 @@ exe = EXE(
|
||||
icon="icons/sabnzbd.ico",
|
||||
version=version_info,
|
||||
target_arch="universal2",
|
||||
entitlements_file="builder/osx/entitlements.plist",
|
||||
codesign_identity=codesign_identity,
|
||||
)
|
||||
|
||||
coll = COLLECT(exe, pyi_analysis.binaries, pyi_analysis.zipfiles, pyi_analysis.datas, name="SABnzbd")
|
||||
@@ -189,4 +198,10 @@ if sys.platform == "darwin":
|
||||
"LSEnvironment": {"LANG": "en_US.UTF-8", "LC_ALL": "en_US.UTF-8"},
|
||||
}
|
||||
|
||||
app = BUNDLE(coll, name="SABnzbd.app", icon="builder/osx/image/sabnzbdplus.icns", info_plist=info_plist)
|
||||
app = BUNDLE(
|
||||
coll,
|
||||
name="SABnzbd.app",
|
||||
icon="builder/osx/image/sabnzbdplus.icns",
|
||||
bundle_identifier="org.sabnzbd.sabnzbd",
|
||||
info_plist=info_plist,
|
||||
)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Special requirements for macOS universal2 binary release
|
||||
# This way dependabot can auto-update them
|
||||
cryptography==36.0.1
|
||||
cryptography==38.0.3
|
||||
@@ -16,6 +16,7 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import glob
|
||||
import hashlib
|
||||
import platform
|
||||
import re
|
||||
import sys
|
||||
@@ -30,6 +31,7 @@ import urllib.error
|
||||
import configobj
|
||||
import pkginfo
|
||||
import github
|
||||
from typing import List
|
||||
|
||||
|
||||
VERSION_FILE = "sabnzbd/version.py"
|
||||
@@ -79,12 +81,12 @@ def delete_files_glob(name):
|
||||
os.remove(f)
|
||||
|
||||
|
||||
def run_external_command(command):
|
||||
def run_external_command(command: List[str], print_output: bool = True):
|
||||
"""Wrapper to ease the use of calling external programs"""
|
||||
process = subprocess.Popen(command, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
output, _ = process.communicate()
|
||||
ret = process.wait()
|
||||
if output:
|
||||
if (output and print_output) or ret != 0:
|
||||
print(output)
|
||||
if ret != 0:
|
||||
raise RuntimeError("Command returned non-zero exit code %s!" % ret)
|
||||
@@ -134,7 +136,7 @@ def test_sab_binary(binary_path: str):
|
||||
try:
|
||||
urllib.request.urlopen(base_url, timeout=1).read()
|
||||
break
|
||||
except urllib.error.URLError:
|
||||
except:
|
||||
time.sleep(1)
|
||||
else:
|
||||
raise urllib.error.URLError("Could not connect to SABnzbd")
|
||||
@@ -304,28 +306,17 @@ if __name__ == "__main__":
|
||||
notarization_user = os.environ.get("NOTARIZATION_USER")
|
||||
notarization_pass = os.environ.get("NOTARIZATION_PASS")
|
||||
|
||||
# Run PyInstaller and check output
|
||||
run_external_command([sys.executable, "-O", "-m", "PyInstaller", "SABnzbd.spec"])
|
||||
|
||||
# Make sure we created a fully universal2 release when releasing or during CI
|
||||
if RELEASE_THIS or ON_GITHUB_ACTIONS:
|
||||
for bin_to_check in glob.glob("dist/SABnzbd.app/Contents/MacOS/**/*.so", recursive=True):
|
||||
print("Checking if binary is universal2: %s" % bin_to_check)
|
||||
file_output = run_external_command(["file", bin_to_check])
|
||||
# Make sure we have both arm64 and x86
|
||||
if not ("x86_64" in file_output and "arm64" in file_output):
|
||||
raise RuntimeError("Non-universal2 binary found!")
|
||||
|
||||
# Only continue if we can sign
|
||||
# We need to sign all the included binaries before packaging them
|
||||
# Otherwise the signature of the main application becomes invalid
|
||||
if authority:
|
||||
files_to_sign = [
|
||||
"dist/SABnzbd.app/Contents/MacOS/osx/par2/par2-sl64",
|
||||
"dist/SABnzbd.app/Contents/MacOS/osx/7zip/7za",
|
||||
"dist/SABnzbd.app/Contents/MacOS/osx/unrar/unrar",
|
||||
"dist/SABnzbd.app/Contents/MacOS/SABnzbd",
|
||||
"dist/SABnzbd.app",
|
||||
"osx/par2/par2-sl64",
|
||||
"osx/par2/arm64/par2",
|
||||
"osx/par2/arm64/libomp.dylib",
|
||||
"osx/unrar/unrar",
|
||||
"osx/unrar/arm64/unrar",
|
||||
"osx/7zip/7zz",
|
||||
]
|
||||
|
||||
for file_to_sign in files_to_sign:
|
||||
print("Signing %s with hardended runtime" % file_to_sign)
|
||||
run_external_command(
|
||||
@@ -338,15 +329,55 @@ if __name__ == "__main__":
|
||||
"runtime",
|
||||
"--entitlements",
|
||||
"builder/osx/entitlements.plist",
|
||||
"-i",
|
||||
"org.sabnzbd.sabnzbd",
|
||||
"-s",
|
||||
authority,
|
||||
file_to_sign,
|
||||
],
|
||||
print_output=False,
|
||||
)
|
||||
print("Signed %s!" % file_to_sign)
|
||||
|
||||
# Run PyInstaller and check output
|
||||
run_external_command([sys.executable, "-O", "-m", "PyInstaller", "SABnzbd.spec"])
|
||||
|
||||
# Make sure we created a fully universal2 release when releasing or during CI
|
||||
if RELEASE_THIS or ON_GITHUB_ACTIONS:
|
||||
for bin_to_check in glob.glob("dist/SABnzbd.app/Contents/MacOS/**/*.so", recursive=True):
|
||||
print("Checking if binary is universal2: %s" % bin_to_check)
|
||||
file_output = run_external_command(["file", bin_to_check], print_output=False)
|
||||
# Make sure we have both arm64 and x86
|
||||
if not ("x86_64" in file_output and "arm64" in file_output):
|
||||
raise RuntimeError("Non-universal2 binary found!")
|
||||
|
||||
# Only continue if we can sign
|
||||
if authority:
|
||||
# We use PyInstaller to sign the main SABnzbd executable and the SABnzbd.app
|
||||
files_already_signed = [
|
||||
"dist/SABnzbd.app/Contents/MacOS/SABnzbd",
|
||||
"dist/SABnzbd.app",
|
||||
]
|
||||
for file_to_check in files_already_signed:
|
||||
print("Checking signature of %s" % file_to_check)
|
||||
sign_result = run_external_command(
|
||||
[
|
||||
"codesign",
|
||||
"-dv",
|
||||
"-r-",
|
||||
file_to_check,
|
||||
],
|
||||
print_output=False,
|
||||
) + run_external_command(
|
||||
[
|
||||
"codesign",
|
||||
"--verify",
|
||||
"--deep",
|
||||
file_to_check,
|
||||
],
|
||||
print_output=False,
|
||||
)
|
||||
if authority not in sign_result or "adhoc" in sign_result or "invalid" in sign_result:
|
||||
raise RuntimeError("Signature of %s seems invalid!" % file_to_check)
|
||||
|
||||
# Only notarize for real builds that we want to deploy
|
||||
if notarization_user and notarization_pass and RELEASE_THIS:
|
||||
# Prepare zip to upload to notarization service
|
||||
@@ -452,6 +483,16 @@ if __name__ == "__main__":
|
||||
# Remove source folder
|
||||
safe_remove(src_folder)
|
||||
|
||||
# Calculate hashes for Synology release
|
||||
with open(RELEASE_SRC, "rb") as inp_file:
|
||||
source_data = inp_file.read()
|
||||
|
||||
print("----")
|
||||
print(RELEASE_SRC, "SHA1", hashlib.sha1(source_data).hexdigest())
|
||||
print(RELEASE_SRC, "SHA256", hashlib.sha256(source_data).hexdigest())
|
||||
print(RELEASE_SRC, "MD5", hashlib.md5(source_data).hexdigest())
|
||||
print("----")
|
||||
|
||||
# Release to github
|
||||
if "release" in sys.argv:
|
||||
# Check if tagged as release and check for token
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
# Basic build requirements
|
||||
# Note that not all sub-dependencies are listed, but only ones we know could cause trouble
|
||||
pyinstaller==4.8
|
||||
pyinstaller-hooks-contrib==2022.0
|
||||
altgraph==0.17.2
|
||||
wrapt==1.13.3
|
||||
setuptools==60.6.0
|
||||
pkginfo==1.8.2
|
||||
PyGithub==1.55
|
||||
charset-normalizer==2.0.11
|
||||
pyinstaller==5.6.1
|
||||
pyinstaller-hooks-contrib==2022.10
|
||||
altgraph==0.17.3
|
||||
wrapt==1.14.1
|
||||
setuptools==65.5.0
|
||||
pkginfo==1.8.3
|
||||
PyGithub==1.56
|
||||
charset-normalizer==3.0.0
|
||||
certifi
|
||||
|
||||
# orjson does not support 32bit Windows, exclude it based on Python-version
|
||||
# This way we also test ujson on Python 3.7 and 3.8 in the CI-tests
|
||||
orjson==3.8.0; python_version > '3.8'
|
||||
|
||||
# For the macOS build
|
||||
dmgbuild==1.5.2; sys_platform == 'darwin'
|
||||
mac-alias==2.2.0; sys_platform == 'darwin'
|
||||
macholib==1.15.2; sys_platform == 'darwin'
|
||||
macholib==1.16.2; sys_platform == 'darwin'
|
||||
ds-store==1.3.0; sys_platform == 'darwin'
|
||||
PyNaCl==1.5.0; sys_platform == 'darwin'
|
||||
PyNaCl==1.5.0; sys_platform == 'darwin'
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="modal-body">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<!--#if not $nt#-->
|
||||
<!--#if not $windows#-->
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" id="show_hidden_folders"> <span>$T('systemFolders')</span>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Config"#-->
|
||||
<!--#set global $help_uri="configuration/3.5/configure"#-->
|
||||
<!--#set global $help_uri="configuration/3.7/configure"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<!--#from sabnzbd.encoding import CODEPAGE#-->
|
||||
@@ -41,7 +41,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
<!--#end if#-->
|
||||
<!--#if not $nt and not $darwin#-->
|
||||
<!--#if not $windows and not $macos#-->
|
||||
<tr>
|
||||
<th scope="row">$T('opt-multicore-par2')</th>
|
||||
<td>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Categories"#-->
|
||||
<!--#set global $help_uri="configuration/3.5/categories"#-->
|
||||
<!--#set global $help_uri="configuration/3.7/categories"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
<div class="colmask">
|
||||
<div class="section">
|
||||
@@ -111,7 +111,7 @@
|
||||
});
|
||||
|
||||
// Add autocomplete and file-browser
|
||||
\$('.fileBrowserSmall').typeahead().fileBrowser();
|
||||
\$('.fileBrowserSmall').typeahead({appendTo: 'body'}).fileBrowser();
|
||||
|
||||
// Make categories sortable
|
||||
\$('.padTable').sortable({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Folders"#-->
|
||||
<!--#set global $help_uri="configuration/3.5/folders"#-->
|
||||
<!--#set global $help_uri="configuration/3.7/folders"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<div class="colmask">
|
||||
@@ -47,7 +47,7 @@
|
||||
<input type="checkbox" name="fulldisk_autoresume" id="fulldisk_autoresume" value="1" <!--#if int($fulldisk_autoresume) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-fulldisk_autoresume')</span>
|
||||
</div>
|
||||
<!--#if not $nt#-->
|
||||
<!--#if not $windows#-->
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="permissions">$T('opt-permissions')</label>
|
||||
<input type="text" name="permissions" id="permissions" value="$permissions" class="smaller_input" />
|
||||
@@ -104,6 +104,11 @@
|
||||
<span class="desc">$T('explain-admin_dir1')</span>
|
||||
<span class="desc">$T('explain-admin_dir2')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="backup_dir">$T('opt-backup_dir')</label>
|
||||
<input type="text" name="backup_dir" id="backup_dir" value="$backup_dir" data-initialdir="$my_home" />
|
||||
<span class="desc">$T('explain-backup_dir')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="log_dir">$T('opt-log_dir')</label>
|
||||
<input type="text" name="log_dir" id="log_dir" value="$log_dir" data-initialdir="$my_lcldata" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="General"#-->
|
||||
<!--#set global $help_uri="configuration/3.5/general"#-->
|
||||
<!--#set global $help_uri="configuration/3.7/general"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<div class="colmask">
|
||||
@@ -9,220 +9,247 @@
|
||||
</label>
|
||||
</div>
|
||||
<form action="saveGeneral" method="post" name="fullform" class="fullform" autocomplete="off">
|
||||
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
|
||||
<input type="hidden" id="ajax" name="ajax" value="1" />
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('webServer') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<p><b>$T('restartRequired')</b></p>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="host">$T('opt-host')</label>
|
||||
<input type="text" name="host" id="host" value="$host" />
|
||||
<span class="desc">$T('explain-host')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="port">$T('opt-port')</label>
|
||||
<input type="number" name="port" id="port" value="$port" size="8" data-original="$port" />
|
||||
<span class="desc">$T('explain-port')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="enable_https">$T('opt-enable_https')</label>
|
||||
<input type="checkbox" name="enable_https" id="enable_https" value="1" <!--#if int($enable_https) > 0 then 'checked="checked" data-original="1"' else ""#-->/>
|
||||
<span class="desc">$T('explain-enable_https')</span>
|
||||
<span class="desc"><span class="label label-warning">$T('warning').upper()</span> $T('explain-enable_https_warning')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="web_dir">$T('opt-web_dir')</label>
|
||||
<select name="web_dir" id="web_dir">
|
||||
<!--#for $webline in $web_list#-->
|
||||
<!--#if $webline.lower() == $web_dir.lower()#-->
|
||||
<option value="$webline" selected="selected">$webline</option>
|
||||
<!--#else#-->
|
||||
<option value="$webline">$webline</option>
|
||||
<!--#end if#-->
|
||||
<!--#end for#-->
|
||||
</select>
|
||||
<span class="desc">$T('explain-web_dir') <a href="$caller_url">$caller_url</a></span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="language">$T('opt-language')</label>
|
||||
<select name="language" id="language" class="select">
|
||||
<!--#for $webline in $lang_list#-->
|
||||
<!--#if $webline[0].lower() == $language.lower()#-->
|
||||
<option value="$webline[0]" selected="selected">$webline[1]</option>
|
||||
<!--#else#-->
|
||||
<option value="$webline[0]">$webline[1]</option>
|
||||
<!--#end if#-->
|
||||
<!--#end for#-->
|
||||
</select>
|
||||
<span class="desc">$T('explain-language')</span>
|
||||
<div class="alert alert-info alert-translate">
|
||||
$T('explain-ask-language') <a href="https://sabnzbd.org/wiki/translate" target="_blank" class="alert-link">https://sabnzbd.org/wiki/translate</a>
|
||||
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
|
||||
<input type="hidden" id="ajax" name="ajax" value="1" />
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('webServer') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<p><b>$T('restartRequired')</b></p>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="host">$T('opt-host')</label>
|
||||
<input type="text" name="host" id="host" value="$host" />
|
||||
<span class="desc">$T('explain-host')</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<h5 class="darkred nomargin">$T('base-folder'): <span class="path">$my_lcldata</span></h5>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_port">$T('opt-https_port')</label>
|
||||
<input type="number" name="https_port" id="https_port" value="$https_port" size="8" data-original="$https_port" />
|
||||
<span class="desc">$T('explain-https_port')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_cert">$T('opt-https_cert')</label>
|
||||
<input type="text" name="https_cert" id="https_cert" value="$https_cert" />
|
||||
<button class="btn btn-default generate_cert" title="$T('explain-new-cert')">
|
||||
<span class="glyphicon glyphicon-repeat"></span>
|
||||
</button>
|
||||
<span class="desc">$T('explain-https_cert')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_key">$T('opt-https_key')</label>
|
||||
<input type="text" name="https_key" id="https_key" value="$https_key" />
|
||||
<button class="btn btn-default generate_cert" title="$T('explain-new-cert')">
|
||||
<span class="glyphicon glyphicon-repeat"></span>
|
||||
</button>
|
||||
<span class="desc">$T('explain-https_key')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_chain">$T('opt-https_chain')</label>
|
||||
<input type="text" name="https_chain" id="https_chain" value="$https_chain" />
|
||||
<span class="desc">$T('explain-https_chain')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default sabnzbd_restart"><span class="glyphicon glyphicon-refresh"></span> $T('button-restart') SABnzbd</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('security') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<p><b>$T('restartRequired')</b></p>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<!-- Tricks to avoid browser auto-fill, fixed on-submit with javascript -->
|
||||
<div class="field-pair">
|
||||
<label class="config" for="${pid}_wu">$T('opt-web_username')</label>
|
||||
<input type="text" name="${pid}_wu" id="${pid}_wu" value="$username" data-hide="username" />
|
||||
<span class="desc">$T('explain-web_username')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="${pid}_wp">$T('opt-web_password')</label>
|
||||
<input type="text" name="${pid}_wp" id="${pid}_wp" value="$password" data-hide="password" />
|
||||
<span class="desc">$T('explain-web_password')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="inet_exposure">$T('opt-inet_exposure')</label>
|
||||
<select name="inet_exposure" id="inet_exposure" class="select">
|
||||
<optgroup label="API">
|
||||
<option value="0" <!--#if $inet_exposure == 0 then 'selected="selected"' else ""#-->>$T('inet-local')</option>
|
||||
<option value="1" <!--#if $inet_exposure == 1 then 'selected="selected"' else ""#-->>$T('inet-nzb')</option>
|
||||
<option value="2" <!--#if $inet_exposure == 2 then 'selected="selected"' else ""#-->>$T('inet-api')</option>
|
||||
<option value="3" <!--#if $inet_exposure == 3 then 'selected="selected"' else ""#-->>$T('inet-fullapi')</option>
|
||||
</optgroup>
|
||||
<optgroup label="$T('inet-fullapi') & $T('opt-web_dir')">
|
||||
<option value="4" <!--#if $inet_exposure == 4 then 'selected="selected"' else ""#-->>$T('inet-ui')</option>
|
||||
<option value="5" <!--#if $inet_exposure == 5 then 'selected="selected"' else ""#-->>$T('inet-ui') - $T('inet-external_login')</option>
|
||||
</optgroup>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="port">$T('opt-port')</label>
|
||||
<input type="number" name="port" id="port" value="$port" size="8" data-original="$port" />
|
||||
<span class="desc">$T('explain-port')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="enable_https">$T('opt-enable_https')</label>
|
||||
<input type="checkbox" name="enable_https" id="enable_https" value="1" <!--#if int($enable_https) > 0 then 'checked="checked" data-original="1"' else ""#-->/>
|
||||
<span class="desc">$T('explain-enable_https')</span>
|
||||
<span class="desc"><span class="label label-warning">$T('warning').upper()</span> $T('explain-enable_https_warning')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="web_dir">$T('opt-web_dir')</label>
|
||||
<select name="web_dir" id="web_dir">
|
||||
<!--#for $webline in $web_list#-->
|
||||
<!--#if $webline.lower() == $web_dir.lower()#-->
|
||||
<option value="$webline" selected="selected">$webline</option>
|
||||
<!--#else#-->
|
||||
<option value="$webline">$webline</option>
|
||||
<!--#end if#-->
|
||||
<!--#end for#-->
|
||||
</select>
|
||||
<span class="desc">$T('explain-inet_exposure')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="apikey_display">$T('opt-apikey')</label>
|
||||
<input type="text" id="apikey_display" class="fileBrowserField" value="$apikey" readonly />
|
||||
<button class="btn btn-default show_qrcode" title="$T('explain-qr-code')" rel="$apikey" ><span class="glyphicon glyphicon-qrcode"></span></button>
|
||||
<button class="btn btn-default generate_key" id="generate_new_apikey" title="$T('button-apikey')"><span class="glyphicon glyphicon-repeat"></span></button>
|
||||
<span class="desc">$T('explain-apikey')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="nzbkey">$T('opt-nzbkey')</label>
|
||||
<input type="text" id="nzbkey" class="fileBrowserField" value="$nzb_key" readonly />
|
||||
<button class="btn btn-default show_qrcode" title="$T('explain-qr-code')" rel="$nzb_key" ><span class="glyphicon glyphicon-qrcode"></span></button>
|
||||
<button class="btn btn-default generate_key" id="generate_new_nzbkey" title="$T('button-apikey')"><span class="glyphicon glyphicon-repeat"></span></button>
|
||||
<span class="desc">$T('explain-nzbkey')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('cmenu-switches') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="auto_browser">$T('opt-auto_browser')</label>
|
||||
<input type="checkbox" name="auto_browser" id="auto_browser" value="1" <!--#if int($auto_browser) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-auto_browser')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="check_new_rel">$T('opt-check_new_rel')</label>
|
||||
<select name="check_new_rel" id="check_new_rel">
|
||||
<option value="0" <!--#if $check_new_rel == 0 then 'selected="selected"' else ""#--> >$T('off')</option>
|
||||
<option value="1" <!--#if $check_new_rel == 1 then 'selected="selected"' else ""#--> >$T('on')</option>
|
||||
<option value="2" <!--#if $check_new_rel == 2 then 'selected="selected"' else ""#--> >$T('also-test')</option>
|
||||
</select>
|
||||
<span class="desc">$T('explain-check_new_rel')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings <!--#if int($certificate_validation) == 0 then "disabled" else ""#-->">
|
||||
<label class="config" for="enable_https_verification">$T('opt-enable_https_verification')</label>
|
||||
<input type="checkbox" name="enable_https_verification" id="enable_https_verification" value="1" <!--#if int($enable_https_verification) > 0 then 'checked="checked"' else ""#--> <!--#if int($certificate_validation) == 0 then "disabled=\"disabled\"" else ""#--> />
|
||||
<span class="desc">$T('explain-enable_https_verification')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="socks5_proxy_url">$T('opt-socks5_proxy_url')</label>
|
||||
<input type="text" name="socks5_proxy_url" id="socks5_proxy_url" value="$socks5_proxy_url" placeholder="socks5://username:password@hostname:port" />
|
||||
<span class="desc">$T('explain-socks5_proxy_url') <br/>$T('readwiki')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('tuning') <a href="$helpuri$help_uri#toc2" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair value-and-select">
|
||||
<label class="config" for="bandwidth_max_value">$T('opt-bandwidth_max')</label>
|
||||
<input type="number" name="bandwidth_max_value" id="bandwidth_max_value" class="smaller_input" />
|
||||
<select name="bandwidth_max_dropdown" id="bandwidth_max_dropdown">
|
||||
<option value="">B/s</option>
|
||||
<option value="K">KB/s</option>
|
||||
<option value="M" selected>MB/s</option>
|
||||
</select>
|
||||
<input type="hidden" name="bandwidth_max" id="bandwidth_max" value="$bandwidth_max" />
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="bandwidth_perc">$T('opt-bandwidth_perc')</label>
|
||||
<input type="number" name="bandwidth_perc" id="bandwidth_perc" value="$bandwidth_perc" step="10" min="0" max="100"/>
|
||||
<span class="desc">$T('explain-bandwidth_perc')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="cache_limit">$T('opt-cache_limitstr')</label>
|
||||
<input type="text" name="cache_limit" id="cache_limit" value="$cache_limit" class="smaller_input" />
|
||||
<span class="desc">$T('explain-cache_limitstr').replace("64M", "256M").replace("128M", "512M")</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
<span class="desc">$T('explain-web_dir') <a href="$caller_url">$caller_url</a></span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="language">$T('opt-language')</label>
|
||||
<select name="language" id="language" class="select">
|
||||
<!--#for $webline in $lang_list#-->
|
||||
<!--#if $webline[0].lower() == $language.lower()#-->
|
||||
<option value="$webline[0]" selected="selected">$webline[1]</option>
|
||||
<!--#else#-->
|
||||
<option value="$webline[0]">$webline[1]</option>
|
||||
<!--#end if#-->
|
||||
<!--#end for#-->
|
||||
</select>
|
||||
<span class="desc">$T('explain-language')</span>
|
||||
<div class="alert alert-info alert-translate">
|
||||
$T('explain-ask-language') <a href="https://sabnzbd.org/wiki/translate" target="_blank" class="alert-link">https://sabnzbd.org/wiki/translate</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<h5 class="darkred nomargin">$T('base-folder'): <span class="path">$my_lcldata</span></h5>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_port">$T('opt-https_port')</label>
|
||||
<input type="number" name="https_port" id="https_port" value="$https_port" size="8" data-original="$https_port" />
|
||||
<span class="desc">$T('explain-https_port')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_cert">$T('opt-https_cert')</label>
|
||||
<input type="text" name="https_cert" id="https_cert" value="$https_cert" />
|
||||
<button class="btn btn-default generate_cert" title="$T('explain-new-cert')">
|
||||
<span class="glyphicon glyphicon-repeat"></span>
|
||||
</button>
|
||||
<span class="desc">$T('explain-https_cert')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_key">$T('opt-https_key')</label>
|
||||
<input type="text" name="https_key" id="https_key" value="$https_key" />
|
||||
<button class="btn btn-default generate_cert" title="$T('explain-new-cert')">
|
||||
<span class="glyphicon glyphicon-repeat"></span>
|
||||
</button>
|
||||
<span class="desc">$T('explain-https_key')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="https_chain">$T('opt-https_chain')</label>
|
||||
<input type="text" name="https_chain" id="https_chain" value="$https_chain" />
|
||||
<span class="desc">$T('explain-https_chain')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default sabnzbd_restart"><span class="glyphicon glyphicon-refresh"></span> $T('button-restart') SABnzbd</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('security') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<p><b>$T('restartRequired')</b></p>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<!-- Tricks to avoid browser auto-fill, fixed on-submit with javascript -->
|
||||
<div class="field-pair">
|
||||
<label class="config" for="${pid}_wu">$T('opt-web_username')</label>
|
||||
<input type="text" name="${pid}_wu" id="${pid}_wu" value="$username" data-hide="username" />
|
||||
<span class="desc">$T('explain-web_username')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="${pid}_wp">$T('opt-web_password')</label>
|
||||
<input type="text" name="${pid}_wp" id="${pid}_wp" value="$password" data-hide="password" />
|
||||
<span class="desc">$T('explain-web_password')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="inet_exposure">$T('opt-inet_exposure')</label>
|
||||
<select name="inet_exposure" id="inet_exposure" class="select">
|
||||
<optgroup label="API">
|
||||
<option value="0" <!--#if $inet_exposure == 0 then 'selected="selected"' else ""#-->>$T('inet-local')</option>
|
||||
<option value="1" <!--#if $inet_exposure == 1 then 'selected="selected"' else ""#-->>$T('inet-nzb')</option>
|
||||
<option value="2" <!--#if $inet_exposure == 2 then 'selected="selected"' else ""#-->>$T('inet-api')</option>
|
||||
<option value="3" <!--#if $inet_exposure == 3 then 'selected="selected"' else ""#-->>$T('inet-fullapi')</option>
|
||||
</optgroup>
|
||||
<optgroup label="$T('inet-fullapi') & $T('opt-web_dir')">
|
||||
<option value="4" <!--#if $inet_exposure == 4 then 'selected="selected"' else ""#-->>$T('inet-ui')</option>
|
||||
<option value="5" <!--#if $inet_exposure == 5 then 'selected="selected"' else ""#-->>$T('inet-ui') - $T('inet-external_login')</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<span class="desc">$T('explain-inet_exposure')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="apikey_display">$T('opt-apikey')</label>
|
||||
<input type="text" id="apikey_display" class="fileBrowserField" value="$apikey" readonly />
|
||||
<button class="btn btn-default show_qrcode" title="$T('explain-qr-code')" rel="$apikey" ><span class="glyphicon glyphicon-qrcode"></span></button>
|
||||
<button class="btn btn-default generate_key" id="generate_new_apikey" title="$T('button-apikey')"><span class="glyphicon glyphicon-repeat"></span></button>
|
||||
<span class="desc">$T('explain-apikey')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="nzbkey">$T('opt-nzbkey')</label>
|
||||
<input type="text" id="nzbkey" class="fileBrowserField" value="$nzb_key" readonly />
|
||||
<button class="btn btn-default show_qrcode" title="$T('explain-qr-code')" rel="$nzb_key" ><span class="glyphicon glyphicon-qrcode"></span></button>
|
||||
<button class="btn btn-default generate_key" id="generate_new_nzbkey" title="$T('button-apikey')"><span class="glyphicon glyphicon-repeat"></span></button>
|
||||
<span class="desc">$T('explain-nzbkey')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('cmenu-switches') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="auto_browser">$T('opt-auto_browser')</label>
|
||||
<input type="checkbox" name="auto_browser" id="auto_browser" value="1" <!--#if int($auto_browser) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-auto_browser')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="check_new_rel">$T('opt-check_new_rel')</label>
|
||||
<select name="check_new_rel" id="check_new_rel">
|
||||
<option value="0" <!--#if $check_new_rel == 0 then 'selected="selected"' else ""#--> >$T('off')</option>
|
||||
<option value="1" <!--#if $check_new_rel == 1 then 'selected="selected"' else ""#--> >$T('on')</option>
|
||||
<option value="2" <!--#if $check_new_rel == 2 then 'selected="selected"' else ""#--> >$T('also-test')</option>
|
||||
</select>
|
||||
<span class="desc">$T('explain-check_new_rel')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings <!--#if int($certificate_validation) == 0 then "disabled" else ""#-->">
|
||||
<label class="config" for="enable_https_verification">$T('opt-enable_https_verification')</label>
|
||||
<input type="checkbox" name="enable_https_verification" id="enable_https_verification" value="1" <!--#if int($enable_https_verification) > 0 then 'checked="checked"' else ""#--> <!--#if int($certificate_validation) == 0 then "disabled=\"disabled\"" else ""#--> />
|
||||
<span class="desc">$T('explain-enable_https_verification')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="socks5_proxy_url">$T('opt-socks5_proxy_url')</label>
|
||||
<input type="text" name="socks5_proxy_url" id="socks5_proxy_url" value="$socks5_proxy_url" autocomplete="off" placeholder="socks5://user:pass@hostname:port" />
|
||||
<span class="desc">$T('explain-socks5_proxy_url') <br/>$T('readwiki')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('tuning') <a href="$helpuri$help_uri#toc2" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair value-and-select">
|
||||
<label class="config" for="bandwidth_max_value">$T('opt-bandwidth_max')</label>
|
||||
<input type="number" name="bandwidth_max_value" id="bandwidth_max_value" class="smaller_input" />
|
||||
<select name="bandwidth_max_dropdown" id="bandwidth_max_dropdown">
|
||||
<option value="">B/s</option>
|
||||
<option value="K">KB/s</option>
|
||||
<option value="M" selected>MB/s</option>
|
||||
</select>
|
||||
<input type="hidden" name="bandwidth_max" id="bandwidth_max" value="$bandwidth_max" />
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="bandwidth_perc">$T('opt-bandwidth_perc')</label>
|
||||
<input type="number" name="bandwidth_perc" id="bandwidth_perc" value="$bandwidth_perc" step="10" min="0" max="100"/>
|
||||
<span class="desc">$T('explain-bandwidth_perc')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="cache_limit">$T('opt-cache_limitstr')</label>
|
||||
<input type="text" name="cache_limit" id="cache_limit" value="$cache_limit" class="smaller_input" />
|
||||
<span class="desc">$T('explain-cache_limitstr').replace("64M", "256M").replace("128M", "512M")</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
</form>
|
||||
|
||||
<form action="uploadConfig" method="post" name="fullform" class="fullform" autocomplete="off" enctype="multipart/form-data">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="ajax" value="1" />
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('backup') <a href="$helpuri$help_uri#toc3" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="create_backup">$T('create-backup')</label>
|
||||
<span class="desc"><button class="btn btn-default createBackup" type="button" id="create_backup"><span class="glyphicon glyphicon glyphicon-import"></span> $T('create-backup')</button></span>
|
||||
<span class="desc">$T('explain-create_backup')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="config_backup_file">$T('restore-backup')</label>
|
||||
<input type="file" accept=".zip" name="config_backup_file" id="config_backup_file" />
|
||||
<span class="desc">$T('restartRequired')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-open"></span> $T('restore-backup')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div><!-- /colmask -->
|
||||
|
||||
@@ -372,6 +399,20 @@
|
||||
}
|
||||
})
|
||||
|
||||
\$('#create_backup').click(function () {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../../api",
|
||||
data: {mode:'config', name:'create_backup', output:'json', apikey: \$('#apikey').val()},
|
||||
success: function(data) {
|
||||
if(data.value.result) {
|
||||
alert("$T('backup'):\n" + data.value.message)
|
||||
} else {
|
||||
alert("$T('button-failed')")
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Email"#-->
|
||||
<!--#set global $help_uri="configuration/3.5/notifications"#-->
|
||||
<!--#set global $help_uri="configuration/3.7/notifications"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<!--#def show_notify_checkboxes($section_label)#-->
|
||||
@@ -124,7 +124,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
<!--#if $nt#-->
|
||||
<!--#if $windows#-->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('section-AC')</h3>
|
||||
@@ -178,7 +178,7 @@
|
||||
<!--#end if#-->
|
||||
<div class="section" id="nscript">
|
||||
<div class="col2">
|
||||
<h3>$T('section-NScript')</h3>
|
||||
<h3>$T('section-NScript') <a href="$helpuri$help_uri#nscript" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
<table>
|
||||
<tr>
|
||||
<td><input type="checkbox" name="nscript_enable" id="nscript_enable" value="1" <!--#if int($nscript_enable) > 0 then 'checked="checked"' else ""#--> /></td>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="RSS"#-->
|
||||
<!--#set global $help_uri="configuration/3.5/rss"#-->
|
||||
<!--#set global $help_uri="configuration/3.7/rss"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
<!--#import html#-->
|
||||
<div class="colmask">
|
||||
@@ -481,18 +481,22 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="default-sort">$T('rss-added')</th>
|
||||
<th>$T('rss-filter')</th>
|
||||
<th>$T('size')</th>
|
||||
<th width="60%">$T('sort-title')</th>
|
||||
<th>$T('category')</th>
|
||||
<th>$T('nzo-age')</th>
|
||||
<th>$T('source')</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!--#for $job in $downloaded#-->
|
||||
<tr class="infoTableSeperator">
|
||||
<td data-sort-value="$job['time_downloaded_ms']">$job['time_downloaded']</td>
|
||||
<td>$job['rule'] $job['skip']</td>
|
||||
<td data-sort-value="$job['size']">$job['size_units']</td>
|
||||
<td>$job['title']</td>
|
||||
<td>$job['cat']</td>
|
||||
<td data-sort-value="$job['age_ms']">$job['age']</td>
|
||||
<td data-sort-value="$job['baselink']" title="$job['baselink']">
|
||||
<!--#if not $job['infourl']#-->
|
||||
<div class="favicon source-icon" style="background-image: url(//$job['baselink']/favicon.ico);" data-domain="$job['baselink']"></div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Scheduling"#-->
|
||||
<!--#set global $help_uri="configuration/3.5/scheduling"#-->
|
||||
<!--#set global $help_uri="configuration/3.7/scheduling"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<%
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Servers"#-->
|
||||
<!--#set global $help_uri="configuration/3.5/servers"#-->
|
||||
<!--#set global $help_uri="configuration/3.7/servers"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<!--#import json#-->
|
||||
@@ -49,7 +49,7 @@
|
||||
<label class="config" for="host">$T('srv-host')</label>
|
||||
<input type="text" name="host" id="host" required />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="port">$T('srv-port')</label>
|
||||
<input type="number" name="port" id="port" size="8" value="119" min="0" />
|
||||
</div>
|
||||
@@ -180,7 +180,7 @@
|
||||
<label class="config" for="host$cur">$T('srv-host')</label>
|
||||
<input type="text" name="host" id="host$cur" value="$server['host']" required />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="port$cur">$T('srv-port')</label>
|
||||
<input type="number" name="port" id="port$cur" value="$server['port']" size="8" min="0" required />
|
||||
</div>
|
||||
@@ -259,7 +259,7 @@
|
||||
<label class="config" for="notes$cur">$T('srv-notes')</label>
|
||||
<textarea name="notes" id="notes$cur" rows="3" cols="50">$server['notes']</textarea>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default testServer" type="button"><span class="glyphicon glyphicon-sort"></span> $T('button-testServer')</button>
|
||||
<button class="btn btn-default delServer"><span class="glyphicon glyphicon-trash"></span> $T('button-delServer')</button>
|
||||
@@ -283,7 +283,8 @@
|
||||
|
||||
<p title="$T('readwiki')">
|
||||
<b>$T('srv-article-availability'):</b><br/>
|
||||
$T('selectedDates'): <span id="server-article-value-${cur}"></span>
|
||||
$T('selectedDates'): <span id="server-article-value-${cur}"></span><br/>
|
||||
<a href="https://sabnzbd.org/not-complete" id="server-article-not-complete-${cur}" target="_blank">https://sabnzbd.org/not-complete</a>
|
||||
</p>
|
||||
<!--#if $server['expire_date']#-->
|
||||
<p><b>$T('srv-expire_date'):</b> $(server['expire_date'])</p>
|
||||
@@ -402,8 +403,11 @@
|
||||
if(!isNaN(articleRatio)) {
|
||||
// Use filesize to convert to unit-display
|
||||
\$('#server-article-value-' + server_id).text('$T("srv-articles-tried")'.replace('%f', articleRatio).replace('%d', filesize(totalArticlesTriedThisRange, {unix: true, round: 0, spacer: "", base: 1})))
|
||||
// If we have a low value, we link them to the website
|
||||
if(articleRatio > 60) \$('#server-article-not-complete-' + server_id).hide()
|
||||
} else {
|
||||
\$('#server-article-value-' + server_id).text('$T("notAvailable")')
|
||||
\$('#server-article-not-complete-' + server_id).hide()
|
||||
}
|
||||
|
||||
// Save bandwidth data in a very ugly way, but we need to do this
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Sorting"#-->
|
||||
<!--#set global $help_uri="configuration/3.5/sorting"#-->
|
||||
<!--#set global $help_uri="configuration/3.7/sorting"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<div class="colmask">
|
||||
@@ -242,10 +242,6 @@
|
||||
<label class="config wide" for="enable_movie_sorting">$T('opt-movieSort')</label>
|
||||
<input type="checkbox" name="enable_movie_sorting" id="enable_movie_sorting" value="1" <!--#if int($enable_movie_sorting)> 0 then 'checked="checked"' else ""#--> />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config wide" for="movie_extra_folder">$T('opt-movieExtra')</label>
|
||||
<input type="checkbox" name="movie_extra_folder" id="movie_extra_folder" value="1" <!--#if int($movie_extra_folder)> 0 then 'checked="checked"' else ""#--> />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="moviefoldername">$T('sortString')</label>
|
||||
<input type="text" name="movie_sort_string" id="moviefoldername" value="$movie_sort_string" /><button class="btn btn-default clearBtn" type="button"><span class="glyphicon glyphicon-remove"></span> $T('button-clear')</button>
|
||||
@@ -257,9 +253,9 @@
|
||||
<div class="field-pair">
|
||||
<label class="config">$T('presetSort')</label>
|
||||
<div class="presets float-left">
|
||||
<input type="button" class="btn btn-default" onclick="movieSet('%title (%y)/%title (%y).%ext',' CD%1');movieExtraFolder(false)" value="$T('button-inFolders')" />
|
||||
<input type="button" class="btn btn-default" onclick="movieSet('%title (%y).%ext',' CD%1');movieExtraFolder(true)" value="$T('button-noFolders')" />
|
||||
<input type="button" class="btn btn-default" onclick="movieSet('%0decade/%title (%y).%ext',' CD%1');movieExtraFolder(true)" value="$T('decade')" />
|
||||
<input type="button" class="btn btn-default" onclick="movieSet('%title (%y)/%title (%y).%ext',' CD%1');" value="$T('button-inFolders')" />
|
||||
<input type="button" class="btn btn-default" onclick="movieSet('%title (%y).%ext',' CD%1');" value="$T('button-noFolders')" />
|
||||
<input type="button" class="btn btn-default" onclick="movieSet('%0decade/%title (%y).%ext',' CD%1');" value="$T('decade')" />
|
||||
<input type="button" class="btn btn-default" onclick="movieSet('%dn.%ext')" value="$T('button-FileLikeFolder')" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -642,10 +638,6 @@
|
||||
new_previewmovie();
|
||||
}
|
||||
|
||||
function movieExtraFolder(value) {
|
||||
\$('#movie_extra_folder').attr("checked", value);
|
||||
}
|
||||
|
||||
function dateSet(val) {
|
||||
\$('#datefoldername').val(val);
|
||||
new_previewdate();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Special"#-->
|
||||
<!--#set global $help_uri="configuration/3.5/special"#-->
|
||||
<!--#set global $help_uri="configuration/3.7/special"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<div class="colmask">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#set global $pane="Switches"#-->
|
||||
<!--#set global $help_uri="configuration/3.5/switches"#-->
|
||||
<!--#set global $help_uri="configuration/3.7/switches"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<div class="colmask">
|
||||
@@ -141,6 +141,7 @@
|
||||
<label class="config" for="auto_sort">$T('opt-auto_sort')</label>
|
||||
<select name="auto_sort" id="auto_sort">
|
||||
<option value="">$T('default')</option>
|
||||
<option value="remaining asc" <!--#if $auto_sort == "remaining asc" then 'selected="selected"' else ""#--> >$T('Glitter-sortRemaining')</option>
|
||||
<option value="avg_age desc" <!--#if $auto_sort == "avg_age desc" then 'selected="selected"' else ""#--> >$T('Glitter-sortAgeAsc')</option>
|
||||
<option value="avg_age asc" <!--#if $auto_sort == "avg_age asc" then 'selected="selected"' else ""#--> >$T('Glitter-sortAgeDesc')</option>
|
||||
<option value="name asc" <!--#if $auto_sort == "name asc" then 'selected="selected"' else ""#--> >$T('Glitter-sortNameAsc')</option>
|
||||
@@ -148,7 +149,7 @@
|
||||
<option value="size asc" <!--#if $auto_sort == "size asc" then 'selected="selected"' else ""#--> >$T('Glitter-sortSizeAsc')</option>
|
||||
<option value="size desc" <!--#if $auto_sort == "size desc" then 'selected="selected"' else ""#--> >$T('Glitter-sortSizeDesc')</option>
|
||||
</select>
|
||||
<span class="desc">$T('explain-auto_sort')</span>
|
||||
<span class="desc">$T('explain-auto_sort') $T('explain-auto_sort_remaining')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="direct_unpack">$T('opt-direct_unpack')</label>
|
||||
@@ -178,7 +179,7 @@
|
||||
<input type="checkbox" name="enable_all_par" id="enable_all_par" value="1" <!--#if int($enable_all_par) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-enable_all_par').replace('. ', '.<br/>')</span>
|
||||
</div>
|
||||
<!--#if not $nt#-->
|
||||
<!--#if not $windows#-->
|
||||
<div class="field-pair advanced-settings <!--#if not $have_nice then "disabled" else "" #-->">
|
||||
<label class="config" for="nice">$T('opt-nice')</label>
|
||||
<input type="text" name="nice" id="nice" value="$nice" <!--#if not $have_nice then 'readonly="readonly" disabled="disabled"' else "" #--> />
|
||||
@@ -247,11 +248,6 @@
|
||||
<input type="checkbox" name="deobfuscate_final_filenames" id="deobfuscate_final_filenames" value="1" <!--#if int($deobfuscate_final_filenames) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-deobfuscate_final_filenames') $T('explain-deobfuscate_final_filenames-ext')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="enable_meta">$T('opt-enable_meta')</label>
|
||||
<input type="checkbox" name="enable_meta" id="enable_meta" value="1" <!--#if int($enable_meta) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-enable_meta').replace('. ', '.<br/>')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="cleanup_list">$T('opt-cleanup_list')</label>
|
||||
<input type="text" name="cleanup_list" id="cleanup_list" value="$cleanup_list"/>
|
||||
@@ -292,12 +288,17 @@
|
||||
<input type="checkbox" name="replace_spaces" id="replace_spaces" value="1" <!--#if int($replace_spaces) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-replace_spaces')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="replace_underscores">$T('opt-replace_underscores')</label>
|
||||
<input type="checkbox" name="replace_underscores" id="replace_underscores" value="1" <!--#if int($replace_underscores) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-replace_underscores')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="replace_dots">$T('opt-replace_dots')</label>
|
||||
<input type="checkbox" name="replace_dots" id="replace_dots" value="1" <!--#if int($replace_dots) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-replace_dots')</span>
|
||||
</div>
|
||||
<!--#if not $nt#-->
|
||||
<!--#if not $windows#-->
|
||||
<div class="field-pair">
|
||||
<label class="config" for="sanitize_safe">$T('opt-sanitize_safe')</label>
|
||||
<input type="checkbox" name="sanitize_safe" id="sanitize_safe" value="1" <!--#if int($sanitize_safe) > 0 then 'checked="checked"' else ""#--> />
|
||||
@@ -348,149 +349,11 @@
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('swtag-indexing') <a href="$helpuri$help_uri#toc6" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="rating_enable">$T('opt-rating_enable')</label>
|
||||
<input type="checkbox" name="rating_enable" id="rating_enable" value="1" <!--#if int($rating_enable) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-rating_enable').replace('. ', '.<br/>')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="rating_api_key">$T('opt-rating_api_key')</label>
|
||||
<input type="text" name="rating_api_key" id="rating_api_key" value="$rating_api_key" />
|
||||
<span class="desc">$T('explain-rating_api_key')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="rating_filter_enable">$T('opt-rating_filter_enable')</label>
|
||||
<input type="checkbox" name="rating_filter_enable" id="rating_filter_enable" value="1" <!--#if int($rating_filter_enable) > 0 then 'checked="checked"' else ""#--> />
|
||||
<span class="desc">$T('explain-rating_filter_enable')</span>
|
||||
</div>
|
||||
<div class="field-pair" id="rating_filter_abort">
|
||||
<label class="config">$T('opt-rating_filter_abort_if')</label>
|
||||
<div class="rating-filter">
|
||||
<p>
|
||||
<label for="rating_filter_abort_video">$T('opt-rating_filter_video')</label>
|
||||
<select name="rating_filter_abort_video" id="rating_filter_abort_video">
|
||||
<option value="0" <!--#if $rating_filter_abort_video == 0 then 'selected="selected"' else ""#--> >$T('notUsed')</option>
|
||||
<!--#for $val in $range(1, 10)#--><option value="$val" <!--#if $rating_filter_abort_video == $val then 'selected="selected"' else ""#--> >$val $T('orLess')</option><!--#end for#-->
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="rating_filter_abort_audio">$T('opt-rating_filter_audio')</label>
|
||||
<select name="rating_filter_abort_audio" id="rating_filter_abort_audio">
|
||||
<option value="0" <!--#if $rating_filter_abort_audio == 0 then 'selected="selected"' else ""#--> >$T('notUsed')</option>
|
||||
<!--#for $val in $range(1, 10)#--><option value="$val" <!--#if $rating_filter_abort_audio == $val then 'selected="selected"' else ""#--> >$val $T('orLess')</option><!--#end for#-->
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_abort_encrypted" name="rating_filter_abort_encrypted" <!--#if int($rating_filter_abort_encrypted) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_abort_encrypted">$T('opt-rating_filter_passworded')</label>
|
||||
</span>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_abort_encrypted_confirm" name="rating_filter_abort_encrypted_confirm" <!--#if int($rating_filter_abort_encrypted_confirm) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_abort_encrypted_confirm">$T('opt-rating_filter_confirmed')</label>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_abort_spam" name="rating_filter_abort_spam" <!--#if int($rating_filter_abort_spam) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_abort_spam">$T('opt-rating_filter_spam')</label>
|
||||
</span>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_abort_spam_confirm" name="rating_filter_abort_spam_confirm" <!--#if int($rating_filter_abort_spam_confirm) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_abort_spam_confirm">$T('opt-rating_filter_confirmed')</label>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<input type="checkbox" value="1" id="rating_filter_abort_downvoted" name="rating_filter_abort_downvoted" <!--#if int($rating_filter_abort_downvoted) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_abort_downvoted">$T('opt-rating_filter_downvoted')</label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="rating_filter_abort_keywords">$T('opt-rating_filter_keywords')</label>
|
||||
<input type="text" name="rating_filter_abort_keywords" id="rating_filter_abort_keywords" value="$rating_filter_abort_keywords"/>
|
||||
<span class="desc">$T('explain-rating_filter_keywords')</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-pair" id="rating_filter_pause">
|
||||
<label class="config">$T('opt-rating_filter_pause_if')</label>
|
||||
<div class="rating-filter">
|
||||
<p>
|
||||
<label for="rating_filter_pause_video">$T('opt-rating_filter_video')</label>
|
||||
<select name="rating_filter_pause_video" id="rating_filter_pause_video">
|
||||
<option value="0" <!--#if $rating_filter_pause_video == 0 then 'selected="selected"' else ""#--> >$T('notUsed')</option>
|
||||
<!--#for $val in $range(1, 10)#--><option value="$val" <!--#if $rating_filter_pause_video == $val then 'selected="selected"' else ""#--> >$val $T('orLess')</option><!--#end for#-->
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="rating_filter_pause_audio">$T('opt-rating_filter_audio')</label>
|
||||
<select name="rating_filter_pause_audio" id="rating_filter_pause_audio">
|
||||
<option value="0" <!--#if $rating_filter_pause_audio == 0 then 'selected="selected"' else ""#--> >$T('notUsed')</option>
|
||||
<!--#for $val in $range(1, 10)#--><option value="$val" <!--#if $rating_filter_pause_audio == $val then 'selected="selected"' else ""#--> >$val $T('orLess') </option><!--#end for#-->
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_pause_encrypted" name="rating_filter_pause_encrypted" <!--#if int($rating_filter_pause_encrypted) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_pause_encrypted">$T('opt-rating_filter_passworded')</label>
|
||||
</span>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_pause_encrypted_confirm" name="rating_filter_pause_encrypted_confirm" <!--#if int($rating_filter_pause_encrypted_confirm) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_pause_encrypted_confirm">$T('opt-rating_filter_confirmed')</label>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_pause_spam" name="rating_filter_pause_spam" <!--#if int($rating_filter_pause_spam) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_pause_spam">$T('opt-rating_filter_spam')</label>
|
||||
</span>
|
||||
<span>
|
||||
<input type="checkbox" value="1" id="rating_filter_pause_spam_confirm" name="rating_filter_pause_spam_confirm" <!--#if int($rating_filter_pause_spam_confirm) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_pause_spam_confirm">$T('opt-rating_filter_confirmed')</label>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<input type="checkbox" value="1" id="rating_filter_pause_downvoted" name="rating_filter_pause_downvoted" <!--#if int($rating_filter_pause_downvoted) > 0 then 'checked="checked"' else ""#--> />
|
||||
<label for="rating_filter_pause_downvoted">$T('opt-rating_filter_downvoted')</label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="rating_filter_pause_keywords">$T('opt-rating_filter_keywords')</label>
|
||||
<input type="text" name="rating_filter_pause_keywords" id="rating_filter_pause_keywords" value="$rating_filter_pause_keywords"/>
|
||||
<span class="desc">$T('explain-rating_filter_keywords')</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div><!-- /col1 -->
|
||||
</div><!-- /section -->
|
||||
</form>
|
||||
</div><!-- /colmask -->
|
||||
|
||||
<script type="text/javascript">
|
||||
\$(document).ready(function() {
|
||||
if (!\$('#rating_filter_enable').is(":checked")) {
|
||||
\$("#rating_filter_abort").hide();
|
||||
\$("#rating_filter_pause").hide();
|
||||
}
|
||||
\$('#rating_filter_enable').change(function () {
|
||||
if (\$(this).is(":checked")) {
|
||||
\$("#rating_filter_abort").show();
|
||||
\$("#rating_filter_pause").show();
|
||||
}
|
||||
else {
|
||||
\$("#rating_filter_abort").hide();
|
||||
\$("#rating_filter_pause").hide();
|
||||
}
|
||||
});
|
||||
|
||||
\$('#history_retention_select, #history_retention_number').on('change', updateHistoryRetention)
|
||||
function updateHistoryRetention() {
|
||||
var retention_setting = \$('#history_retention')
|
||||
|
||||
@@ -139,6 +139,9 @@ label.wide,
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
}
|
||||
.desc .btn {
|
||||
font-style: normal;
|
||||
}
|
||||
.desc.narrow {
|
||||
margin: 0 0 0 200px!important;
|
||||
}
|
||||
@@ -724,41 +727,6 @@ ul.tabs li.active a {
|
||||
.checkbox-days label {
|
||||
padding: 2px 20px;
|
||||
}
|
||||
.rating-filter {
|
||||
float: left;
|
||||
}
|
||||
.rating-filter p {
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
.rating-filter select {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.rating-filter input {
|
||||
vertical-align: middle;
|
||||
margin-top: -1px;
|
||||
}
|
||||
.rating-filter label {
|
||||
display: inline-block;
|
||||
padding-left: 0px;
|
||||
width: 100px;
|
||||
}
|
||||
.rating-filter input[type="checkbox"] {
|
||||
display: inline;
|
||||
}
|
||||
.rating-filter input[type="checkbox"] + label {
|
||||
padding-left: 20px;
|
||||
padding-top: 5px;
|
||||
width: auto;
|
||||
}
|
||||
.rating-filter p > span:first-child {
|
||||
float: left;
|
||||
width: 130px;
|
||||
}
|
||||
.rating-filter .desc {
|
||||
display: block;
|
||||
margin: 0px;
|
||||
padding-left: 103px;
|
||||
}
|
||||
|
||||
/** EDITS 2015 **/
|
||||
* {
|
||||
|
||||
@@ -215,7 +215,7 @@ $.fn.extractFormDataTo = function(target) {
|
||||
* (c) 2015 SABnzbd Team, Inc. All rights reserved.
|
||||
*/
|
||||
function config_success() {
|
||||
$('.saveButton').each(function () {
|
||||
$('.saveButton[disabled=disabled]').each(function () {
|
||||
$(this).removeAttr("disabled").html('<span class="glyphicon glyphicon-ok"></span> '+configTranslate.saveChanges);
|
||||
});
|
||||
// Let us leave!
|
||||
@@ -223,7 +223,7 @@ function config_success() {
|
||||
formHasChanged = false;
|
||||
}
|
||||
function config_failure() {
|
||||
$('.saveButton').each(function () {
|
||||
$('.saveButton[disabled=disabled]').each(function () {
|
||||
$(this).removeAttr("disabled").addClass('btn-danger').html('<span class="glyphicon glyphicon-remove"></span> '+configTranslate.failed);
|
||||
});
|
||||
// Can't go yet..
|
||||
@@ -345,8 +345,9 @@ $(document).ready(function () {
|
||||
datatype: 'json',
|
||||
// But first remove Obfuscation!
|
||||
beforeSerialize: removeObfuscation,
|
||||
beforeSubmit: function () {
|
||||
$('.saveButton').each(function () {
|
||||
beforeSubmit: function (arr, form, options) {
|
||||
// Only in the current form
|
||||
form.find('.saveButton').each(function () {
|
||||
$(this).attr("disabled", "disabled").removeClass('btn-danger').html('<span class="glyphicon glyphicon-transfer"></span> ' + configTranslate.saving);
|
||||
});
|
||||
},
|
||||
@@ -407,7 +408,7 @@ $(document).ready(function () {
|
||||
$('input[type="checkbox"]').parents('label').addClass('config-hover')
|
||||
|
||||
// Disable sections
|
||||
var checkDisabled = '#rating_enable, #enable_tv_sorting, #enable_movie_sorting, #enable_date_sorting'
|
||||
var checkDisabled = '#enable_tv_sorting, #enable_movie_sorting, #enable_date_sorting'
|
||||
|
||||
$(checkDisabled).on('change', function() {
|
||||
$(this).parent().nextAll().toggleClass('disabled')
|
||||
|
||||
@@ -41,102 +41,11 @@
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="name" data-bind="css: { 'name-has-ratings' : historyStatus.has_rating }">
|
||||
<td class="name">
|
||||
<div class="row-wrap-text">
|
||||
<a class="retry-buttontext" href="#" data-bind="visible: (failed() && canRetry()), click: retry">$T('button-retry')</a>
|
||||
<span data-bind="text: historyStatus.name, attr: { 'title': historyStatus.name() }"></span>
|
||||
</div>
|
||||
|
||||
<!-- ko if: historyStatus.has_rating -->
|
||||
<div class="dropdown history-ratings">
|
||||
<a href="#" class="name-icons hover-button" data-toggle="dropdown" onclick="keepOpen(this)">
|
||||
<span class="glyphicon glyphicon-thumbs-up"></span> <span data-bind="text: historyStatus.rating_avg_vote_up"></span>
|
||||
<span class="glyphicon glyphicon-thumbs-down"></span> <span data-bind="text: historyStatus.rating_avg_vote_down"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu history-ratings-menu">
|
||||
<li>
|
||||
<form class="history-ratings-basic">
|
||||
<label>
|
||||
<input type="radio" value="up" data-bind="attr: { 'name': 'ratings-status-'+nzo_id, 'checked': historyStatus.rating_user_vote() == 1 }, event: { change: setUserVote }" />
|
||||
<span class="glyphicon glyphicon-thumbs-up"></span>
|
||||
<span data-bind="text: historyStatus.rating_avg_vote_up"></span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" value="down" data-bind="attr: { 'name': 'ratings-status-'+nzo_id, 'checked': historyStatus.rating_user_vote() == 2 }, event: { change: setUserVote }" />
|
||||
<span class="glyphicon glyphicon-thumbs-down"></span>
|
||||
<span data-bind="text: historyStatus.rating_avg_vote_down"></span>
|
||||
</label>
|
||||
<label>
|
||||
<span class="glyphicon glyphicon-facetime-video"></span>
|
||||
<select name="ratings-video" data-bind="value: historyStatus.rating_user_video, event: { change: setUserRating }, disable: historyStatus.rating_user_video">
|
||||
<option value=""> </option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="7">7</option>
|
||||
<option value="8">8</option>
|
||||
<option value="9">9</option>
|
||||
<option value="10">10</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span class="glyphicon glyphicon-volume-up"></span>
|
||||
<select name="ratings-audio" data-bind="value: historyStatus.rating_user_audio, event: { change: setUserRating }, disable: historyStatus.rating_user_audio">
|
||||
<option value=""> </option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="7">7</option>
|
||||
<option value="8">8</option>
|
||||
<option value="9">9</option>
|
||||
<option value="10">10</option>
|
||||
</select>
|
||||
</label>
|
||||
<!-- ko if: historyStatus.url_info -->
|
||||
<a href="#" target="_blank" data-bind="attr: { 'href':historyStatus.url_info }" title="$T('Glitter-openInfoURL')"><span class="glyphicon glyphicon-globe"></span></a>
|
||||
<!-- /ko -->
|
||||
</form>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<form class="history-ratings-report" data-bind="submit: setUserReport">
|
||||
<strong>$T('report')</strong>
|
||||
<br />
|
||||
<label>
|
||||
<input type="radio" name="rating_flag" value="spam" /> $T('spam')
|
||||
</label>
|
||||
<br />
|
||||
<label>
|
||||
<input type="radio" name="rating_flag" value="encrypted" /> $T('encrypted')
|
||||
</label>
|
||||
<br />
|
||||
<label>
|
||||
<input type="radio" name="rating_flag" value="expired" /> $T('expired')
|
||||
<select name="ratings-report-expired-server" class="ratings-report-hidden form-control" data-bind="options: \$parent.servers, optionsText: 'host', optionsValue: 'host', optionsCaption: '$T('nzo-all')'"></select>
|
||||
</label>
|
||||
<br />
|
||||
<label>
|
||||
<input type="radio" name="rating_flag" value="other" /> $T('otherProblem')
|
||||
<input type="text" class="form-control ratings-report-hidden" name="ratings-report-other" />
|
||||
</label>
|
||||
<br />
|
||||
<label>
|
||||
<input type="radio" name="rating_flag" value="comment" /> $T('comment')
|
||||
<input type="text" class="form-control ratings-report-hidden" name="ratings-report-comment" />
|
||||
</label>
|
||||
<br />
|
||||
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-ok"></span> $T('send')</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
</td>
|
||||
<td class="status row-wrap-text" data-bind="text: statusText()" onclick="showDetails(this)"></td>
|
||||
<!-- ko foreach: parent.parent.extraHistoryColumns -->
|
||||
@@ -177,7 +86,7 @@
|
||||
<div class="col-sm-2">$T('srv-password')</div>
|
||||
<div class="col-sm-10" data-bind="text: historyStatus.password"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="row" data-bind="visible: historyStatus.storage() || historyStatus.path()">
|
||||
<div class="col-sm-2">$T('msg-path')</div>
|
||||
<div class="col-sm-10" data-bind="text: historyStatus.storage() == '' ? historyStatus.path : historyStatus.storage"></div>
|
||||
</div>
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<button type="button" class="btn btn-default navbar-btn dropdown-toggle" data-toggle="dropdown" onclick="keepOpen(this)">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<a href="#" class="max-speed-input-clear hover-button" data-bind="click: clearSpeedLimit, visible:(speedLimit() != 100)" style="display: none;">
|
||||
<a href="#" class="max-speed-input-clear hover-button" data-bind="click: clearSpeedLimit, visible:(speedLimit() < 100 && speedLimit() > 0)" style="display: none;">
|
||||
<span class="glyphicon glyphicon-link"></span>
|
||||
</a>
|
||||
<div class="dropdown-menu max-speed-input">
|
||||
@@ -81,7 +81,7 @@
|
||||
<li data-tooltip="true" data-placement="bottom" title="SABnzbd $T('menu-config')">
|
||||
<a href="./config/"><span class="glyphicon glyphicon-cog"></span></a>
|
||||
</li>
|
||||
<li class="dropdown main-menu-link" data-bind="css: { 'active-on-queue-finish-menu': onQueueFinish()}">
|
||||
<li class="dropdown main-menu-link" data-bind="css: { 'active-on-queue-finish-menu': finishaction()}">
|
||||
<a href="#" data-toggle="dropdown" onclick="keepOpen(this)">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@@ -102,7 +102,8 @@
|
||||
<li class="divider"></li>
|
||||
<li class="dropdown-header"><span class="glyphicon glyphicon-off"></span> $T('Glitter-onFinish'):</li>
|
||||
<li>
|
||||
<select data-bind="value: onQueueFinish, event: { change: setOnQueueFinish }" class="form-control">
|
||||
<!-- ko if: queue.scriptsListLoaded -->
|
||||
<select data-bind="value: finishaction, event: { change: setOnQueueFinish }" class="form-control">
|
||||
<option value=""></option>
|
||||
<optgroup label="$T('eoq-actions')">
|
||||
<option value="shutdown_program">$T('shutdownSab')</option>
|
||||
@@ -114,12 +115,13 @@
|
||||
</optgroup>
|
||||
<optgroup label="$T('eoq-scripts')" data-bind="visible: queue.scriptsList().length > 1">
|
||||
<!-- ko foreach: queue.scriptsList -->
|
||||
<!-- ko if: \$data != glitterTranslate.noneText -->
|
||||
<option data-bind="text: \$data, attr: { value: 'script_'+\$data } " ></option>
|
||||
<!-- ko if: \$data.scriptValue != 'None' -->
|
||||
<option data-bind="text: \$data.scriptText, attr: { value: 'script_'+\$data.scriptValue } " ></option>
|
||||
<!-- /ko -->
|
||||
<!-- /ko -->
|
||||
</optgroup>
|
||||
</select>
|
||||
<!-- /ko -->
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('dashboard-NameserverDNS') </div>
|
||||
<div class="col-sm-6" data-bind="visible: hasStatusInfo, text: !statusInfo.dnslookup() ? '$T('dashboard-connectionError')' : statusInfo.dnslookup(), css: { 'options-bad-status' : (statusInfo.dnslookup() != 'OK') }"></div>
|
||||
<div class="col-sm-6" data-bind="visible: hasStatusInfo, text: !statusInfo.dnslookup() ? '$T('dashboard-connectionError')' : 'OK', css: { 'options-bad-status' : !statusInfo.dnslookup() }"></div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasStatusInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
<hr/>
|
||||
@@ -117,30 +117,45 @@
|
||||
<span data-bind="text: cacheSize"></span> (<span data-bind="text: cacheArticles"></span> $T('Glitter-articles'))
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" data-bind="visible: statusInfo.loadavg()">
|
||||
<div class="col-sm-6">$T('dashboard-loadavg') </div>
|
||||
<div class="col-sm-6">
|
||||
<span data-bind="text: statusInfo.loadavg"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" data-bind="visible: statusInfo.delayed_decoder() > 5 || statusInfo.delayed_assembler() > 5">
|
||||
<div class="col-sm-6">$T('dashboard-delayed') </div>
|
||||
<div class="col-sm-6">
|
||||
<span data-bind="visible: statusInfo.delayed_decoder() > 5">$T('dashboard-delayed-cpu')</span>
|
||||
<small data-bind="visible: statusInfo.delayed_decoder() > 5">(<span data-bind="text: statusInfo.delayed_decoder"></span>x)</small>
|
||||
<span data-bind="visible: statusInfo.delayed_assembler() > 5">$T('dashboard-delayed-disk')</span>
|
||||
<small data-bind="visible: statusInfo.delayed_assembler() > 5">(<span data-bind="text: statusInfo.delayed_assembler"></span>x)</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('dashboard-systemPerformance') </div>
|
||||
<div class="col-sm-6" data-bind="visible: hasPerformanceInfo">
|
||||
<div class="col-sm-6 col-dot-overflow" data-bind="visible: hasPerformanceInfo">
|
||||
<span data-bind="text: statusInfo.pystone"></span>
|
||||
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<small data-bind="truncatedText: statusInfo.cpumodel, length: 25, attr: { 'data-original-title': statusInfo.cpumodel }" data-tooltip="true"></small>
|
||||
<small title="$cpumodel $cpusimd" data-tooltip="true">$cpumodel $cpusimd</small>
|
||||
</div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('dashboard-downloadDirSpeed') </div>
|
||||
<div class="col-sm-6" data-bind="visible: hasPerformanceInfo">
|
||||
<div class="col-sm-6 col-dot-overflow" data-bind="visible: hasPerformanceInfo">
|
||||
<span data-bind="text: statusInfo.downloaddirspeed()"></span> MB/s
|
||||
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<small>(<span data-bind="truncatedText: statusInfo.downloaddir, length: 24, attr: { 'data-original-title': statusInfo.downloaddir }" data-tooltip="true"></span>)</small>
|
||||
<small data-bind="text: statusInfo.downloaddir, attr: { 'data-original-title': statusInfo.downloaddir }" data-tooltip="true"></small>
|
||||
</div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('dashboard-completeDirSpeed') </div>
|
||||
<div class="col-sm-6" data-bind="visible: hasPerformanceInfo">
|
||||
<div class="col-sm-6 col-dot-overflow" data-bind="visible: hasPerformanceInfo">
|
||||
<span data-bind="text: statusInfo.completedirspeed()"></span> MB/s
|
||||
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<small>(<span data-bind="truncatedText: statusInfo.completedir, length: 24, attr: { 'data-original-title': statusInfo.completedir }" data-tooltip="true"></span>)</small>
|
||||
<small data-bind="text: statusInfo.completedir, attr: { 'data-original-title': statusInfo.completedir }" data-tooltip="true"></small>
|
||||
</div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
@@ -149,7 +164,7 @@
|
||||
<div class="col-sm-6" data-bind="visible: hasPerformanceInfo">
|
||||
<span data-bind="text: statusInfo.internetbandwidth()"></span> MB/s
|
||||
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<small>(<span data-bind="text: statusInfo.internetbandwidth()*8"></span> Mbps)</small>
|
||||
<small><span data-bind="text: statusInfo.internetbandwidth()*8"></span> Mbps</small>
|
||||
</div>
|
||||
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
|
||||
</div>
|
||||
@@ -159,7 +174,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> 1 GB</a>
|
||||
<a href="#" class="btn btn-default" data-bind="click: testDownload" data-size="10GB" data-tooltip="true" data-placement="top" title="$T('dashboard-testDownload-explain')"><span class="glyphicon glyphicon-download-alt"></span> 10 GB</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
@@ -182,7 +196,7 @@
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" data-tooltip="true" data-placement="top" title="$T('logging')">
|
||||
<span class="input-group-addon"><span class="glyphicon glyphicon-comment"></span></span>
|
||||
<select class="form-control" data-bind="value: statusInfo.loglevel">
|
||||
<select class="form-control" data-bind="value: loglevel">
|
||||
<option value="0">$T('log-errWarn')</option>
|
||||
<option value="1">$T('log-info')</option>
|
||||
<option value="2">$T('log-debug')</option>
|
||||
@@ -439,6 +453,14 @@
|
||||
<input type="checkbox" name="confirmDeleteHistory" value="true" data-bind="checked: confirmDeleteHistory" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-checkbox">
|
||||
<label class="col-sm-6 control-label">
|
||||
$T("Glitter-keyboardShortcuts")
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="checkbox" name="keyboardShortcuts" value="true" data-bind="checked: keyboardShortcuts" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -501,7 +523,7 @@
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('category')</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="Category" class="form-control" data-bind="options: queue.categoriesList, optionsValue: 'catValue', optionsText: 'catText',"></select>
|
||||
<select name="Category" class="form-control" data-bind="options: queue.categoriesList, optionsValue: 'catValue', optionsText: 'catText'"></select>
|
||||
<span class="glyphicon glyphicon-tag"></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -522,7 +544,7 @@
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('eoq-scripts')</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="Post-processing" class="form-control" data-bind="options: queue.scriptsList, optionsCaption: '$T('default')', enable: (queue.scriptsList().length > 1)"></select>
|
||||
<select name="Post-processing" class="form-control" data-bind="options: queue.scriptsList, optionsCaption: '$T('default')', optionsValue: 'scriptValue', optionsText: 'scriptText', enable: (queue.scriptsList().length > 1)"></select>
|
||||
<span class="glyphicon glyphicon-flash"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,12 +9,6 @@
|
||||
</a>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<!--#if $loadavg#-->
|
||||
<div class="info-container-box" title="$T('ft-sysload') - $T('menu-config') ➜ $T('cmenu-special') ➜ show_sysload">
|
||||
<span class="glyphicon glyphicon-record"></span>
|
||||
<span data-bind="text: systemLoad"></span>
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
<!-- ko if: (queueDataLeft() != '') -->
|
||||
<div class="info-container-box">
|
||||
<span class="glyphicon glyphicon-save"></span>
|
||||
@@ -52,6 +46,7 @@
|
||||
<span class="glyphicon glyphicon-tasks" data-tooltip="true" data-placement="left" title="$T('Glitter-multiOperations')"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" data-action="sortRemainingAsc" data-bind="click: queue.queueSorting">$T('Glitter-sortRemaining')</a></li>
|
||||
<li><a href="#" data-action="sortAgeAsc" data-bind="click: queue.queueSorting">$T('Glitter-sortAgeAsc')</a></li>
|
||||
<li><a href="#" data-action="sortAgeDesc" data-bind="click: queue.queueSorting">$T('Glitter-sortAgeDesc')</a></li>
|
||||
<li><a href="#" data-action="sortNameAsc" data-bind="click: queue.queueSorting">$T('Glitter-sortNameAsc')</a></li>
|
||||
@@ -162,7 +157,7 @@
|
||||
</li>
|
||||
<li title="$T('eoq-scripts')" data-tooltip="true" data-placement="left">
|
||||
<span class="glyphicon glyphicon-flash"></span>
|
||||
<select name="Post-processing" class="form-control" data-bind="options: parent.scriptsList, value: script, event: { change: changeScript }, enable: (parent.scriptsList().length > 1)"></select>
|
||||
<select name="Post-processing" class="form-control" data-bind="options: parent.scriptsList, value: script, optionsValue: 'scriptValue', optionsText: 'scriptText', event: { change: changeScript }, enable: (parent.scriptsList().length > 1)"></select>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- /ko -->
|
||||
@@ -209,7 +204,7 @@
|
||||
</div>
|
||||
<div class="add-nzb-inputbox" data-tooltip="true" data-placement="top" title="$T('eoq-scripts')">
|
||||
<span class="glyphicon glyphicon-flash"></span>
|
||||
<select name="Post-processing" class="form-control" data-bind="options: queue.scriptsList, optionsCaption: '', event: { change: queue.doMultiEditUpdate }"></select>
|
||||
<select name="Post-processing" class="form-control" data-bind="options: queue.scriptsList, optionsValue: 'scriptValue', optionsText: 'scriptText', optionsCaption: '', event: { change: queue.doMultiEditUpdate }"></select>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</form>
|
||||
|
||||
@@ -65,17 +65,8 @@
|
||||
glitterTranslate.renameAbort = "$T('Glitter-confirmAbortDirectUnpack')\n$T('confirm')";
|
||||
glitterTranslate.retryAll = "$T('link-retryAll')?";
|
||||
glitterTranslate.fetch = "$T('Glitter-fetch')";
|
||||
glitterTranslate.encrypted = "$T('Glitter-encrypted')";
|
||||
glitterTranslate.duplicate = "$T('Glitter-duplicate')";
|
||||
glitterTranslate.tooLarge = "$T('Glitter-tooLarge')";
|
||||
glitterTranslate.unwanted = "$T('Glitter-unwanted')";
|
||||
glitterTranslate.incomplete = "$T('Glitter-incomplete')";
|
||||
glitterTranslate.filtered = "$T('Glitter-filtered')";
|
||||
glitterTranslate.waitSec = "$T('Glitter-waitSec')";
|
||||
glitterTranslate.checking = "$T('post-Checking')";
|
||||
glitterTranslate.misingArt = "$T('missingArt')";
|
||||
glitterTranslate.noSelect = "$T('Glitter-noSelect')";
|
||||
glitterTranslate.sendThanks = "$T('Glitter-sendThanks')";
|
||||
glitterTranslate.chooseFile = "$T('Glitter-chooseFile')";
|
||||
glitterTranslate.orphanedJobsMsg = "$T('explain-orphans')";
|
||||
glitterTranslate.useCache = "$T('explain-cache_limitstr').replace("64M", "256M").replace("128M", "512M")";
|
||||
@@ -103,6 +94,7 @@
|
||||
glitterTranslate.status['Repair'] = "$T('stage-repair')";
|
||||
glitterTranslate.status['Filejoin'] = "$T('stage-filejoin')";
|
||||
glitterTranslate.status['Unpack'] = "$T('stage-unpack')";
|
||||
glitterTranslate.status['Deobfuscate'] = "$T('stage-deobfuscate')";
|
||||
glitterTranslate.status['Script'] = "$T('stage-script')";
|
||||
glitterTranslate.status['Source'] = "$T('stage-source')";
|
||||
glitterTranslate.status['Servers'] = "$T('stage-servers')";
|
||||
@@ -129,9 +121,11 @@
|
||||
<!--#include raw $webdir + "/static/javascripts/jquery-3.5.1.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/jquery-ui.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/jquery.peity.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/jquery.hotkeys.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/moment-2.26.0.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/knockout-3.5.1.min.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/knockout-extensions.js"#-->
|
||||
<!--#include raw $webdir + "/static/javascripts/search-query-parser.js"#-->
|
||||
<!--#include raw $webdir + "/static/bootstrap/js/bootstrap.min.js"#-->
|
||||
<!--#include $webdir + "/static/javascripts/glitter.js"#-->
|
||||
</script>
|
||||
|
||||
@@ -24,7 +24,7 @@ if(isMobile) {
|
||||
}
|
||||
|
||||
// Basic API-call
|
||||
function callAPI(data) {
|
||||
function callAPI(data, timeout = 10000) {
|
||||
// Fill basis var's
|
||||
data.output = "json";
|
||||
data.apikey = apiKey;
|
||||
@@ -33,24 +33,7 @@ function callAPI(data) {
|
||||
type: "GET",
|
||||
cache: false,
|
||||
data: data,
|
||||
timeout: 10000 // Wait a little longer on mobile connections
|
||||
});
|
||||
|
||||
return $.when(ajaxQuery);
|
||||
}
|
||||
|
||||
// Special API call
|
||||
function callSpecialAPI(url, data) {
|
||||
// Did we get input?
|
||||
if(data == undefined) data = {};
|
||||
// Fill basis var's
|
||||
data.output = "json";
|
||||
data.apikey = apiKey;
|
||||
var ajaxQuery = $.ajax({
|
||||
url: url,
|
||||
type: "GET",
|
||||
cache: false,
|
||||
data: data
|
||||
timeout: timeout
|
||||
});
|
||||
|
||||
return $.when(ajaxQuery);
|
||||
|
||||
@@ -294,7 +294,7 @@ function paginationModel(parent) {
|
||||
self.nrPages(1)
|
||||
self.currentStart(0);
|
||||
|
||||
// Are we on next page?
|
||||
// Are we on next page? Bad!
|
||||
if(self.currentPage() > 1) {
|
||||
// Force full update
|
||||
parent.parent.refresh(true);
|
||||
@@ -302,9 +302,6 @@ function paginationModel(parent) {
|
||||
|
||||
// Move to current page
|
||||
self.currentPage(1);
|
||||
|
||||
// Force full update
|
||||
parent.parent.refresh(true);
|
||||
} else {
|
||||
// Calculate number of pages needed
|
||||
var newNrPages = Math.ceil(parent.totalItems() / parent.paginationLimit())
|
||||
|
||||
@@ -10,7 +10,7 @@ function HistoryListModel(parent) {
|
||||
self.historyItems = ko.observableArray([])
|
||||
self.showFailed = ko.observable(false).extend({ persist: 'historyShowFailed' });
|
||||
self.isLoading = ko.observable(false).extend({ rateLimit: 100 });
|
||||
self.searchTerm = ko.observable('').extend({ rateLimit: { timeout: 200, method: "notifyWhenChangesStop" } });
|
||||
self.searchTerm = ko.observable('').extend({ rateLimit: { timeout: 400, method: "notifyWhenChangesStop" } });
|
||||
self.paginationLimit = ko.observable(10).extend({ persist: 'historyPaginationLimit' });
|
||||
self.totalItems = ko.observable(0);
|
||||
self.pagination = new paginationModel(self);
|
||||
@@ -139,14 +139,15 @@ function HistoryListModel(parent) {
|
||||
form.reset()
|
||||
}
|
||||
|
||||
// Searching in history (rate-limited in decleration)
|
||||
// Searching in history (rate-limited in declaration)
|
||||
self.searchTerm.subscribe(function() {
|
||||
// Make sure we refresh
|
||||
self.lastUpdate = 0
|
||||
self.parent.refresh();
|
||||
// Go back to page 1
|
||||
if(self.pagination.currentPage() != 1) {
|
||||
// This forces a refresh
|
||||
self.pagination.moveToPage(1);
|
||||
} else {
|
||||
// Make sure we refresh
|
||||
self.parent.refresh(true);
|
||||
}
|
||||
})
|
||||
|
||||
@@ -157,7 +158,6 @@ function HistoryListModel(parent) {
|
||||
// Set the loader so it doesn't flicker and then switch
|
||||
self.isLoading(true)
|
||||
self.searchTerm('');
|
||||
self.parent.refresh()
|
||||
}
|
||||
// Was it click and the field is empty? Then we focus on the field
|
||||
if(event.type == 'mousedown' && self.searchTerm() == '') {
|
||||
@@ -449,103 +449,4 @@ function HistoryModel(parent, data) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// User voting
|
||||
self.setUserVote = function(item, event) {
|
||||
// Send vote
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'rating',
|
||||
type: 'vote',
|
||||
setting: $(event.target).val(),
|
||||
value: self.nzo_id
|
||||
}).then(function(response) {
|
||||
// Update all info
|
||||
self.updateAllHistory = true;
|
||||
self.parent.parent.refresh(true)
|
||||
})
|
||||
}
|
||||
|
||||
// User rating
|
||||
self.setUserRating = function(item, event) {
|
||||
// Audio or video
|
||||
var changeWhat = 'audio';
|
||||
if($(event.target).attr('name') == 'ratings-video') {
|
||||
changeWhat = 'video';
|
||||
}
|
||||
|
||||
// Only on user-event, not the auto-fired ones
|
||||
if(!event.originalEvent) return;
|
||||
|
||||
// Send vote
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'rating',
|
||||
type: changeWhat,
|
||||
setting: $(event.target).val(),
|
||||
value: self.nzo_id
|
||||
}).then(function(response) {
|
||||
// Update all info
|
||||
self.updateAllHistory = true;
|
||||
self.parent.parent.refresh(true)
|
||||
})
|
||||
}
|
||||
|
||||
// User comment
|
||||
self.setUserReport = function(form) {
|
||||
// What are we reporting?
|
||||
var userReport = $(form).find('input[name="rating_flag"]:checked').val();
|
||||
var userDetail = '';
|
||||
|
||||
// Anything selected?
|
||||
if(!userReport) {
|
||||
alert(glitterTranslate.noSelect)
|
||||
return;
|
||||
}
|
||||
|
||||
// Extra info?
|
||||
if(userReport == 'comment') userDetail = $(form).find('input[name="ratings-report-comment"]').val();
|
||||
if(userReport == 'other') userDetail = $(form).find('input[name="ratings-report-other"]').val();
|
||||
|
||||
// Exception for servers
|
||||
if(userReport == 'expired') {
|
||||
// Which server?
|
||||
userDetail = $(form).find('select[name="ratings-report-expired-server"]').val();
|
||||
|
||||
// All?
|
||||
if(userDetail == "") {
|
||||
// Loop over all servers
|
||||
$.each(parent.parent.servers, function(index, server) {
|
||||
// Set timeout because simultanious requests don't work (yet)
|
||||
setTimeout(function() {
|
||||
submitUserReport(server.name)
|
||||
}, index * 1500)
|
||||
})
|
||||
|
||||
} else {
|
||||
// Just the one server
|
||||
submitUserReport(userDetail)
|
||||
}
|
||||
} else {
|
||||
submitUserReport(userDetail)
|
||||
}
|
||||
|
||||
// After all, close it
|
||||
form.reset();
|
||||
$(form).parent().parent().dropdown('toggle');
|
||||
alert(glitterTranslate.sendThanks)
|
||||
|
||||
function submitUserReport(theDetail) {
|
||||
// Send note
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'rating',
|
||||
type: 'flag',
|
||||
setting: userReport,
|
||||
detail: theDetail,
|
||||
value: self.nzo_id
|
||||
})
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,6 @@ function QueueListModel(parent) {
|
||||
var self = this;
|
||||
self.parent = parent;
|
||||
self.dragging = false;
|
||||
self.rawCatList = [];
|
||||
self.rawScriptList = [];
|
||||
|
||||
// Because SABNZB returns the name
|
||||
// But when you want to set Priority you need the number..
|
||||
@@ -39,7 +37,8 @@ function QueueListModel(parent) {
|
||||
self.multiEditItems = ko.observableArray([]);
|
||||
self.categoriesList = ko.observableArray([]);
|
||||
self.scriptsList = ko.observableArray([]);
|
||||
self.searchTerm = ko.observable('').extend({ rateLimit: { timeout: 200, method: "notifyWhenChangesStop" } });
|
||||
self.scriptsListLoaded = ko.observable(false);
|
||||
self.searchTerm = ko.observable('').extend({ rateLimit: { timeout: 400, method: "notifyWhenChangesStop" } });
|
||||
self.paginationLimit = ko.observable(20).extend({ persist: 'queuePaginationLimit' });
|
||||
self.pagination = new paginationModel(self);
|
||||
|
||||
@@ -66,31 +65,6 @@ function QueueListModel(parent) {
|
||||
return i.id;
|
||||
});
|
||||
|
||||
// Did the category-list change?
|
||||
// Otherwise KO will send updates to all <select> for every refresh()
|
||||
if(self.rawCatList != data.categories.toString()) {
|
||||
// Reformat categories
|
||||
self.categoriesList($.map(data.categories, function(cat) {
|
||||
// Default?
|
||||
if(cat == '*') return { catValue: '*', catText: glitterTranslate.defaultText };
|
||||
return { catValue: cat, catText: cat };
|
||||
}))
|
||||
// Update
|
||||
self.rawCatList = data.categories.toString();
|
||||
}
|
||||
|
||||
// Did the script-list change?
|
||||
if(self.rawScriptList != data.scripts.toString()) {
|
||||
// Reformat script-list
|
||||
self.scriptsList($.map(data.scripts, function(script) {
|
||||
// Default?
|
||||
if(script == 'None') return glitterTranslate.noneText;
|
||||
return script;
|
||||
}))
|
||||
// Update
|
||||
self.rawScriptList = data.scripts.toString();
|
||||
}
|
||||
|
||||
// Set limit
|
||||
self.totalItems(data.noofslots);
|
||||
|
||||
@@ -194,11 +168,13 @@ function QueueListModel(parent) {
|
||||
|
||||
// Searching in queue (rate-limited in decleration)
|
||||
self.searchTerm.subscribe(function() {
|
||||
// Refresh now
|
||||
self.parent.refresh();
|
||||
// Go back to page 1
|
||||
if(self.pagination.currentPage() != 1) {
|
||||
// This forces a refresh
|
||||
self.pagination.moveToPage(1);
|
||||
} else {
|
||||
// Refresh now
|
||||
self.parent.refresh();
|
||||
}
|
||||
})
|
||||
|
||||
@@ -208,7 +184,6 @@ function QueueListModel(parent) {
|
||||
if(event.type == 'mousedown' || (event.keyCode && event.keyCode == 27)) {
|
||||
self.isLoading(true)
|
||||
self.searchTerm('');
|
||||
self.parent.refresh()
|
||||
}
|
||||
// Was it click and the field is empty? Then we focus on the field
|
||||
if(event.type == 'mousedown' && self.searchTerm() == '') {
|
||||
@@ -226,6 +201,10 @@ function QueueListModel(parent) {
|
||||
// What action?
|
||||
var sort, dir;
|
||||
switch($(event.currentTarget).data('action')) {
|
||||
case 'sortRemainingAsc':
|
||||
sort = 'remaining';
|
||||
dir = 'asc';
|
||||
break;
|
||||
case 'sortAgeAsc':
|
||||
sort = 'avg_age';
|
||||
dir = 'desc';
|
||||
@@ -693,8 +672,6 @@ function QueueModel(parent, data) {
|
||||
})
|
||||
}
|
||||
self.changeScript = function(item) {
|
||||
// Not on empty handlers
|
||||
if(!item.script() || parent.scriptsList().length <= 1) return;
|
||||
callAPI({
|
||||
mode: 'change_script',
|
||||
value: item.id,
|
||||
|
||||
12
interfaces/Glitter/templates/static/javascripts/jquery.hotkeys.min.js
vendored
Normal file
12
interfaces/Glitter/templates/static/javascripts/jquery.hotkeys.min.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* jQuery Hotkeys Plugin
|
||||
* Copyright 2010, John Resig
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
*
|
||||
* Based upon the plugin by Tzury Bar Yochay:
|
||||
* https://github.com/tzuryby/jquery.hotkeys
|
||||
*
|
||||
* Original idea by:
|
||||
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
|
||||
*/
|
||||
!function(c){function e(e){var o,f;"string"==typeof e.data&&(e.data={keys:e.data}),e.data&&e.data.keys&&"string"==typeof e.data.keys&&(o=e.handler,f=e.data.keys.toLowerCase().split(" "),e.handler=function(a){if(this===a.target||!(/textarea|select/i.test(a.target.nodeName)||c.hotkeys.options.filterTextInputs&&-1<c.inArray(a.target.type,c.hotkeys.textAcceptingInputTypes))){var s="keypress"!==a.type&&c.hotkeys.specialKeys[a.which],e=String.fromCharCode(a.which).toLowerCase(),r="",t={};c.each(["alt","ctrl","shift"],function(e,t){a[t+"Key"]&&s!==t&&(r+=t+"+")}),a.metaKey&&!a.ctrlKey&&"meta"!==s&&(r+="meta+"),a.metaKey&&"meta"!==s&&-1<r.indexOf("alt+ctrl+shift+")&&(r=r.replace("alt+ctrl+shift+","hyper+")),s?t[r+s]=!0:(t[r+e]=!0,t[r+c.hotkeys.shiftNums[e]]=!0,"shift+"===r&&(t[c.hotkeys.shiftNums[e]]=!0));for(var i=0,n=f.length;i<n;i++)if(t[f[i]])return o.apply(this,arguments)}})}c.hotkeys={version:"0.8",specialKeys:{8:"backspace",9:"tab",10:"return",13:"return",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",59:";",61:"=",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",106:"*",107:"+",109:"-",110:".",111:"/",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",144:"numlock",145:"scroll",173:"-",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},shiftNums:{"`":"~",1:"!",2:"@",3:"#",4:"$",5:"%",6:"^",7:"&",8:"*",9:"(",0:")","-":"_","=":"+",";":": ","'":'"',",":"<",".":">","/":"?","\\":"|"},textAcceptingInputTypes:["text","password","number","email","url","range","date","month","week","time","datetime","datetime-local","search","color","tel"],options:{filterTextInputs:!0}},c.each(["keydown","keyup","keypress"],function(){c.event.special[this]={add:e}})}(jQuery||this.jQuery||window.jQuery);
|
||||
@@ -1,15 +1,3 @@
|
||||
ko.bindingHandlers.truncatedText = {
|
||||
update: function(element, valueAccessor, allBindingsAccessor) {
|
||||
var value = ko.utils.unwrapObservable(valueAccessor());
|
||||
if (!value) return
|
||||
var length = ko.utils.unwrapObservable(allBindingsAccessor().length) || ko.bindingHandlers.truncatedText.defaultLength,
|
||||
truncatedValue = value.length > length ? convertHTMLtoText(value.substring(0, Math.min(value.length, length))) + "…" : convertHTMLtoText(value);
|
||||
ko.bindingHandlers.html.update(element, function() {
|
||||
return truncatedValue;
|
||||
});
|
||||
},
|
||||
defaultLength: 15
|
||||
};
|
||||
ko.bindingHandlers.truncatedTextCenter = {
|
||||
update: function(element, valueAccessor, allBindingsAccessor) {
|
||||
var value = ko.utils.unwrapObservable(valueAccessor())
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
/*!
|
||||
* search-search-query-parser.js
|
||||
* Copyright(c) 2014-2019
|
||||
* MIT Licensed
|
||||
*
|
||||
* Modified for SABnzbd use!
|
||||
* Adapted to use without NPM.
|
||||
*/
|
||||
|
||||
function search_query_parse(string, options) {
|
||||
// Set a default options object when none is provided
|
||||
if (!options) {
|
||||
options = {offsets: true};
|
||||
} else {
|
||||
// If options offsets was't passed, set it to true
|
||||
options.offsets = (typeof options.offsets === 'undefined' ? true : options.offsets)
|
||||
}
|
||||
|
||||
if (!string) {
|
||||
string = '';
|
||||
}
|
||||
|
||||
// When no keywords or ranges set, treat as a simple string
|
||||
else if (!options.keywords && !options.ranges && !options.tokenize) {
|
||||
return string;
|
||||
}
|
||||
// Otherwise parse the advanced query syntax
|
||||
else {
|
||||
// Our object to store the query object
|
||||
var query = {text: []};
|
||||
// When offsets is true, create their array
|
||||
if (options.offsets) {
|
||||
query.offsets = [];
|
||||
}
|
||||
var exclusion = {};
|
||||
var terms = [];
|
||||
// Get a list of search terms respecting single and double quotes
|
||||
var regex = /(\S+:'(?:[^'\\]|\\.)*')|(\S+:"(?:[^"\\]|\\.)*")|(-?"(?:[^"\\]|\\.)*")|(-?'(?:[^'\\]|\\.)*')|\S+|\S+:\S+/g;
|
||||
var match;
|
||||
while ((match = regex.exec(string)) !== null) {
|
||||
var term = match[0];
|
||||
var sepIndex = term.indexOf(':');
|
||||
if (sepIndex !== -1) {
|
||||
var split = term.split(':'),
|
||||
key = term.slice(0, sepIndex),
|
||||
val = term.slice(sepIndex + 1);
|
||||
// Strip surrounding quotes
|
||||
val = val.replace(/^\"|\"$|^\'|\'$/g, '');
|
||||
// Strip backslashes respecting escapes
|
||||
val = (val + '').replace(/\\(.?)/g, function (s, n1) {
|
||||
switch (n1) {
|
||||
case '\\':
|
||||
return '\\';
|
||||
case '0':
|
||||
return '\u0000';
|
||||
case '':
|
||||
return '';
|
||||
default:
|
||||
return n1;
|
||||
}
|
||||
});
|
||||
terms.push({
|
||||
keyword: key,
|
||||
value: val,
|
||||
offsetStart: match.index,
|
||||
offsetEnd: match.index + term.length
|
||||
});
|
||||
} else {
|
||||
var isExcludedTerm = false;
|
||||
if (term[0] === '-') {
|
||||
isExcludedTerm = true;
|
||||
term = term.slice(1);
|
||||
}
|
||||
|
||||
// Strip surrounding quotes
|
||||
term = term.replace(/^\"|\"$|^\'|\'$/g, '');
|
||||
// Strip backslashes respecting escapes
|
||||
term = (term + '').replace(/\\(.?)/g, function (s, n1) {
|
||||
switch (n1) {
|
||||
case '\\':
|
||||
return '\\';
|
||||
case '0':
|
||||
return '\u0000';
|
||||
case '':
|
||||
return '';
|
||||
default:
|
||||
return n1;
|
||||
}
|
||||
});
|
||||
|
||||
if (isExcludedTerm) {
|
||||
if (exclusion['text']) {
|
||||
if (exclusion['text'] instanceof Array) {
|
||||
exclusion['text'].push(term);
|
||||
} else {
|
||||
exclusion['text'] = [exclusion['text']];
|
||||
exclusion['text'].push(term);
|
||||
}
|
||||
} else {
|
||||
// First time seeing an excluded text term
|
||||
exclusion['text'] = term;
|
||||
}
|
||||
} else {
|
||||
terms.push({
|
||||
text: term,
|
||||
offsetStart: match.index,
|
||||
offsetEnd: match.index + term.length
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reverse to ensure proper order when pop()'ing.
|
||||
terms.reverse();
|
||||
// For each search term
|
||||
var term;
|
||||
while (term = terms.pop()) {
|
||||
// When just a simple term
|
||||
if (term.text) {
|
||||
// We add it as pure text
|
||||
query.text.push(term.text);
|
||||
// When offsets is true, push a new offset
|
||||
if (options.offsets) {
|
||||
query.offsets.push(term);
|
||||
}
|
||||
}
|
||||
// We got an advanced search syntax
|
||||
else {
|
||||
var key = term.keyword;
|
||||
// Check if the key is a registered keyword
|
||||
options.keywords = options.keywords || [];
|
||||
var isKeyword = false;
|
||||
var isExclusion = false;
|
||||
if (!/^-/.test(key)) {
|
||||
isKeyword = !(-1 === options.keywords.indexOf(key));
|
||||
} else if (key[0] === '-') {
|
||||
var _key = key.slice(1);
|
||||
isKeyword = !(-1 === options.keywords.indexOf(_key))
|
||||
if (isKeyword) {
|
||||
key = _key;
|
||||
isExclusion = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the key is a registered range
|
||||
options.ranges = options.ranges || [];
|
||||
var isRange = !(-1 === options.ranges.indexOf(key));
|
||||
// When the key matches a keyword
|
||||
if (isKeyword) {
|
||||
// When offsets is true, push a new offset
|
||||
if (options.offsets) {
|
||||
query.offsets.push({
|
||||
keyword: key,
|
||||
value: term.value,
|
||||
offsetStart: isExclusion ? term.offsetStart + 1 : term.offsetStart,
|
||||
offsetEnd: term.offsetEnd
|
||||
});
|
||||
}
|
||||
|
||||
var value = term.value;
|
||||
// When value is a thing
|
||||
if (value.length) {
|
||||
// Get an array of values when several are there
|
||||
var values = value.split(',');
|
||||
if (isExclusion) {
|
||||
if (exclusion[key]) {
|
||||
// ...many times...
|
||||
if (exclusion[key] instanceof Array) {
|
||||
// ...and got several values this time...
|
||||
if (values.length > 1) {
|
||||
// ... concatenate both arrays.
|
||||
exclusion[key] = exclusion[key].concat(values);
|
||||
} else {
|
||||
// ... append the current single value.
|
||||
exclusion[key].push(value);
|
||||
}
|
||||
}
|
||||
// We saw that keyword only once before
|
||||
else {
|
||||
// Put both the current value and the new
|
||||
// value in an array
|
||||
exclusion[key] = [exclusion[key]];
|
||||
exclusion[key].push(value);
|
||||
}
|
||||
}
|
||||
// First time we see that keyword
|
||||
else {
|
||||
// ...and got several values this time...
|
||||
if (values.length > 1) {
|
||||
// ...add all values seen.
|
||||
exclusion[key] = values;
|
||||
}
|
||||
// Got only a single value this time
|
||||
else {
|
||||
// Record its value as a string
|
||||
if (options.alwaysArray) {
|
||||
// ...but we always return an array if option alwaysArray is true
|
||||
exclusion[key] = [value];
|
||||
} else {
|
||||
// Record its value as a string
|
||||
exclusion[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If we already have seen that keyword...
|
||||
if (query[key]) {
|
||||
// ...many times...
|
||||
if (query[key] instanceof Array) {
|
||||
// ...and got several values this time...
|
||||
if (values.length > 1) {
|
||||
// ... concatenate both arrays.
|
||||
query[key] = query[key].concat(values);
|
||||
} else {
|
||||
// ... append the current single value.
|
||||
query[key].push(value);
|
||||
}
|
||||
}
|
||||
// We saw that keyword only once before
|
||||
else {
|
||||
// Put both the current value and the new
|
||||
// value in an array
|
||||
query[key] = [query[key]];
|
||||
query[key].push(value);
|
||||
}
|
||||
}
|
||||
// First time we see that keyword
|
||||
else {
|
||||
// ...and got several values this time...
|
||||
if (values.length > 1) {
|
||||
// ...add all values seen.
|
||||
query[key] = values;
|
||||
}
|
||||
// Got only a single value this time
|
||||
else {
|
||||
if (options.alwaysArray) {
|
||||
// ...but we always return an array if option alwaysArray is true
|
||||
query[key] = [value];
|
||||
} else {
|
||||
// Record its value as a string
|
||||
query[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The key allows a range
|
||||
else if (isRange) {
|
||||
// When offsets is true, push a new offset
|
||||
if (options.offsets) {
|
||||
query.offsets.push(term);
|
||||
}
|
||||
|
||||
var value = term.value;
|
||||
// Range are separated with a dash
|
||||
var rangeValues = value.split('-');
|
||||
// When both end of the range are specified
|
||||
// keyword:XXXX-YYYY
|
||||
query[key] = {};
|
||||
if (2 === rangeValues.length) {
|
||||
query[key].from = rangeValues[0];
|
||||
query[key].to = rangeValues[1];
|
||||
}
|
||||
// When pairs of ranges are specified
|
||||
// keyword:XXXX-YYYY,AAAA-BBBB
|
||||
else if (!rangeValues.length % 2) {
|
||||
}
|
||||
// When only getting a single value,
|
||||
// or an odd number of values
|
||||
else {
|
||||
query[key].from = value;
|
||||
}
|
||||
} else {
|
||||
// We add it as pure text
|
||||
var text = term.keyword + ':' + term.value;
|
||||
query.text.push(text);
|
||||
|
||||
// When offsets is true, push a new offset
|
||||
if (options.offsets) {
|
||||
query.offsets.push({
|
||||
text: text,
|
||||
offsetStart: term.offsetStart,
|
||||
offsetEnd: term.offsetEnd
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Concatenate all text terms if any
|
||||
if (query.text.length) {
|
||||
if (!options.tokenize) {
|
||||
query.text = query.text.join(' ').trim();
|
||||
}
|
||||
}
|
||||
// Just remove the attribute text when it's empty
|
||||
else {
|
||||
delete query.text;
|
||||
}
|
||||
|
||||
// Return forged query object
|
||||
query.exclude = exclusion;
|
||||
return query;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -94,7 +94,8 @@ legend,
|
||||
.nav-tabs>li.active>a,
|
||||
.nav-tabs>li.active>a:focus,
|
||||
.nav-tabs>li.active>a:hover,
|
||||
.nav-tabs>li>a:hover {
|
||||
.nav-tabs>li>a:hover,
|
||||
.nav-tabs>li>a:focus {
|
||||
background-color: #ddd;
|
||||
color: #555 !important;
|
||||
box-shadow: 0px -1px 1px 1px rgba(0,0,0,0.15);
|
||||
|
||||
@@ -1009,10 +1009,6 @@ tr.queue-item>td:first-child>a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.history-table td.name.name-has-ratings .row-wrap-text {
|
||||
max-width: calc(100% - 80px) ;
|
||||
}
|
||||
|
||||
.history-failed-download:hover .retry-button .glyphicon:before,
|
||||
.retry-button:hover .glyphicon:before {
|
||||
content: " \e030 ";
|
||||
@@ -1077,83 +1073,6 @@ tr.queue-item>td:first-child>a {
|
||||
.history-status-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.history-ratings {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.history-ratings.open a {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.history-ratings .name-icons {
|
||||
float: none !important;
|
||||
}
|
||||
|
||||
.history-ratings-menu {
|
||||
width: 300px;
|
||||
padding: 10px;
|
||||
margin-top: 4px !important;
|
||||
}
|
||||
|
||||
.history-ratings-menu .divider {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.history-ratings-menu label {
|
||||
margin-right: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.history-ratings-basic input[type="radio"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.history-ratings-basic input[type="radio"]+span {
|
||||
opacity: 0.6;
|
||||
cursor: pointer;
|
||||
font-size: 1.3em;
|
||||
font-weight: bold;
|
||||
top: 3px;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.history-ratings-basic input[type="radio"]+span+span {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.history-ratings-basic input[type="radio"]:checked+span,
|
||||
.history-ratings-basic input[type="radio"]:checked+span+span {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.history-ratings-basic .history-ratings-spacer {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.history-ratings-basic select {
|
||||
margin-left: 3px;
|
||||
background-color: transparent;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.history-ratings-basic select:disabled {
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
|
||||
.history-ratings-report label {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.history-ratings-report .ratings-report-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.history-ratings-report input[type="radio"]:checked+input,
|
||||
.history-ratings-report input[type="radio"]:checked+select {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#history-options {
|
||||
margin-top: 0;
|
||||
margin-left: 10px;
|
||||
@@ -1370,6 +1289,12 @@ tr.queue-item>td:first-child>a {
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
#modal-options .col-dot-overflow {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#modal-options #options-status .glyphicon:not(.glyphicon-comment) {
|
||||
margin-right: 5px;
|
||||
margin-left: 3px;
|
||||
@@ -1954,10 +1879,6 @@ input[name="nzbURL"] {
|
||||
#feedback-slider {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.glyphicon-facetime-video {
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-device-width:768px) and (max-device-width:1024px) and (orientation:portrait) {
|
||||
@@ -2036,7 +1957,6 @@ a:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.glyphicon-volume-up,
|
||||
.glyphicon-trash {
|
||||
top: 2px;
|
||||
}
|
||||
@@ -2105,15 +2025,6 @@ a:focus {
|
||||
content: '';
|
||||
}
|
||||
|
||||
.history-ratings-menu:after {
|
||||
right: inherit !important;
|
||||
left: 23px;
|
||||
}
|
||||
.history-ratings-menu:before {
|
||||
right: inherit !important;
|
||||
left: 22px;
|
||||
}
|
||||
|
||||
.open > .dropdown-menu {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
|
||||
@@ -180,14 +180,6 @@ tr.queue-item>td:first-child>a {
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
.history-table .history-ratings {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.name-has-ratings .row-wrap-text {
|
||||
max-width: calc(100% - 1px) !important;
|
||||
}
|
||||
|
||||
.history-table .delete .dropdown-menu {
|
||||
width: 100%;
|
||||
left: 0;
|
||||
|
||||
@@ -26,12 +26,13 @@
|
||||
</div>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-xs-4 text-center">
|
||||
<div class="col-md-4 text-center">
|
||||
<a class="btn btn-danger" href="../shutdown/?apikey=$apikey&pid=$pid"><span class="glyphicon glyphicon-remove"></span> $T('wizard-exit')</a>
|
||||
</div>
|
||||
<div class="col-xs-4 text-center">
|
||||
<div class="col-md-4 text-center">
|
||||
<a class="btn btn-default" href="../config/general/#config_backup_file"><span class="glyphicon glyphicon-open"></span> $T('restore-backup')</a>
|
||||
</div>
|
||||
<div class="col-xs-4 text-center">
|
||||
<div class="col-md-4 text-center">
|
||||
<button class="btn btn-default">$T('wizard-start') <span class="glyphicon glyphicon-chevron-right"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
53
linux/org.sabnzbd.sabnzbd.appdata.xml
Normal file
53
linux/org.sabnzbd.sabnzbd.appdata.xml
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright 2022 The SABnzbd-Team <team@sabnzbd.org> -->
|
||||
<component type="desktop-application">
|
||||
<id>org.sabnzbd.sabnzbd</id>
|
||||
<metadata_license>MIT</metadata_license>
|
||||
<name>SABnzbd</name>
|
||||
<summary>Free and easy binary newsreader</summary>
|
||||
<description>
|
||||
<p>
|
||||
SABnzbd is a free and Open Source web-based binary newsreader,
|
||||
with support for the popular nzb file format. It greatly simplifies
|
||||
the process of downloading from Usenet, thanks to a friendly
|
||||
web-based user interface and advanced built-in post-processing
|
||||
options including the ability to automatically verify, repair,
|
||||
extract and clean up downloaded posts. It runs anywhere, comes in
|
||||
over a dozen languages, and integrates with a host of tools, apps
|
||||
and services that help automate the download process.
|
||||
</p>
|
||||
</description>
|
||||
<categories>
|
||||
<category>Network</category>
|
||||
<category>FileTransfer</category>
|
||||
</categories>
|
||||
<url type="homepage">https://sabnzbd.org</url>
|
||||
<url type="bugtracker">https://github.com/sabnzbd/sabnzbd/issues</url>
|
||||
<url type="translate">https://sabnzbd.org/wiki/translate</url>
|
||||
<url type="donation">https://sabnzbd.org/donate</url>
|
||||
<url type="help">https://sabnzbd.org/wiki/</url>
|
||||
<url type="faq">https://sabnzbd.org/wiki/faq</url>
|
||||
<url type="contact">https://forums.sabnzbd.org</url>
|
||||
<launchable type="desktop-id">sabnzbd.desktop</launchable>
|
||||
<provides>
|
||||
<mediatype>application/x-nzb</mediatype>
|
||||
<mediatype>application/x-compressed-nzb</mediatype>
|
||||
</provides>
|
||||
<project_license>GPL-2.0-or-later</project_license>
|
||||
<developer_name>The SABnzbd-team</developer_name>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/interface.png</image>
|
||||
<caption>Web interface</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/night-mode.png</image>
|
||||
<caption>Night mode</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/config.png</image>
|
||||
<caption>Easy configuration</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<content_rating type="oars-1.1"/>
|
||||
</component>
|
||||
9
linux/org.sabnzbd.sabnzbd.sharedmimeinfo
Normal file
9
linux/org.sabnzbd.sabnzbd.sharedmimeinfo
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
|
||||
<mime-type type="application/x-compressed-nzb">
|
||||
<sub-class-of type="application/x-nzb"/>
|
||||
<comment>NewzBin Usenet index (compressed)</comment>
|
||||
<glob pattern="*.nzb.gz"/>
|
||||
<glob pattern="*.nzb.bz2"/>
|
||||
</mime-type>
|
||||
</mime-info>
|
||||
63
linux/sabnzbd.bash-completion
Normal file
63
linux/sabnzbd.bash-completion
Normal file
@@ -0,0 +1,63 @@
|
||||
# bash completion for sabnzbd
|
||||
|
||||
_sabnzbd()
|
||||
{
|
||||
local cur prev words cword split
|
||||
# list all options here
|
||||
local all_options="-f --config-file --pidfile -t --templates --pid -l --logging -w --weblogging -d --daemon -h
|
||||
--help -v --version -c --clean -p --pause --repair --repair-all --no-login --log-all --console
|
||||
--disable-file-log --new -b --browser --ipv6_hosting --inet_exposure --https -s --server"
|
||||
_init_completion -s || return
|
||||
|
||||
# handle options that take arguments
|
||||
case $prev in
|
||||
# 0..1
|
||||
--browser|--ipv6_hosting|-!(-*)[b])
|
||||
COMPREPLY=( $(compgen -W '{0..1}' -- "$cur") )
|
||||
return
|
||||
;;
|
||||
# -1..2
|
||||
--logging|-!(-*)[l])
|
||||
COMPREPLY=( $(compgen -W '{-1..2}' -- "$cur") )
|
||||
return
|
||||
;;
|
||||
# 0..5
|
||||
--inet_exposure)
|
||||
COMPREPLY=( $(compgen -W '{0..5}' -- "$cur") )
|
||||
return
|
||||
;;
|
||||
# directory path
|
||||
--templates|--pid|-!(-*)[t])
|
||||
compopt +o nospace
|
||||
_filedir -d
|
||||
return
|
||||
;;
|
||||
# file path
|
||||
--config-file|--pidfile|-!(-*)[f])
|
||||
compopt +o nospace
|
||||
_filedir
|
||||
return
|
||||
;;
|
||||
# port number
|
||||
--https)
|
||||
COMPREPLY=( $(compgen -W '{0..65535}' -- "$cur") )
|
||||
return
|
||||
;;
|
||||
# host:port
|
||||
--server|-!(-*)[s])
|
||||
# suggest possible formats
|
||||
COMPREPLY=( $(compgen -W 'hostname :port hostname:port ipv4 ipv4:port [ipv6] [ipv6]:port' -- "$cur") )
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
$split && return
|
||||
|
||||
if [[ "$cur" == -* ]]; then
|
||||
COMPREPLY=( $(compgen -W "$all_options" -- "$cur") )
|
||||
else
|
||||
_filedir '@(nzb|nzb.gz|nzb.bz2|zip|rar|7z)'
|
||||
fi
|
||||
|
||||
} &&
|
||||
complete -F _sabnzbd SABnzbd.py sabnzbd sabnzbdplus
|
||||
11
linux/sabnzbd.desktop
Normal file
11
linux/sabnzbd.desktop
Normal file
@@ -0,0 +1,11 @@
|
||||
[Desktop Entry]
|
||||
Name=SABnzbd
|
||||
GenericName=Binary newsreader
|
||||
Comment=Download from Usenet
|
||||
Exec=/opt/sabnzbd/SABnzbd.py --browser 1 %F
|
||||
Icon=sabnzbd
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Network;FileTransfer;
|
||||
Keywords=usenet;binaries;download;nzb;nntp;newsreader;
|
||||
MimeType=application/x-nzb;application/x-compressed-nzb;
|
||||
BIN
osx/7zip/7za
BIN
osx/7zip/7za
Binary file not shown.
BIN
osx/7zip/7zz
Executable file
BIN
osx/7zip/7zz
Executable file
Binary file not shown.
@@ -1,17 +1,21 @@
|
||||
7-Zip source code
|
||||
~~~~~~~~~~~~~~~~~
|
||||
7-Zip
|
||||
~~~~~
|
||||
License for use and distribution
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
7-Zip Copyright (C) 1999-2016 Igor Pavlov.
|
||||
7-Zip Copyright (C) 1999-2021 Igor Pavlov.
|
||||
|
||||
Licenses for files are:
|
||||
The licenses for 7zz file are:
|
||||
|
||||
1) CPP/7zip/Compress/Rar* files: GNU LGPL + unRAR restriction
|
||||
2) All other files: GNU LGPL
|
||||
- The "GNU LGPL" as main license for most of the code
|
||||
- The "GNU LGPL" with "unRAR license restriction" for some code
|
||||
- The "BSD 3-clause License" for some code
|
||||
|
||||
The GNU LGPL + unRAR restriction means that you must follow both
|
||||
GNU LGPL rules and unRAR restriction rules.
|
||||
Redistributions in binary form must reproduce related license information from this file.
|
||||
|
||||
Note:
|
||||
You can use 7-Zip on any computer, including a computer in a commercial
|
||||
organization. You don't need to register or pay for 7-Zip.
|
||||
|
||||
|
||||
GNU LGPL information
|
||||
@@ -27,26 +31,57 @@
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
USA
|
||||
You can receive a copy of the GNU Lesser General Public License from
|
||||
http://www.gnu.org/
|
||||
|
||||
|
||||
unRAR restriction
|
||||
-----------------
|
||||
|
||||
The decompression engine for RAR archives was developed using source
|
||||
|
||||
BSD 3-clause License
|
||||
--------------------
|
||||
|
||||
The "BSD 3-clause License" is used for the code in 7z.dll that implements LZFSE data decompression.
|
||||
That code was derived from the code in the "LZFSE compression library" developed by Apple Inc,
|
||||
that also uses the "BSD 3-clause License":
|
||||
|
||||
----
|
||||
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
----
|
||||
|
||||
|
||||
|
||||
|
||||
unRAR license restriction
|
||||
-------------------------
|
||||
|
||||
The decompression engine for RAR archives was developed using source
|
||||
code of unRAR program.
|
||||
All copyrights to original unRAR code are owned by Alexander Roshal.
|
||||
|
||||
The license for original unRAR code has the following restriction:
|
||||
|
||||
The unRAR sources cannot be used to re-create the RAR compression algorithm,
|
||||
which is proprietary. Distribution of modified unRAR sources in separate form
|
||||
or as a part of other software is permitted, provided that it is clearly
|
||||
stated in the documentation and source comments that the code may
|
||||
not be used to develop a RAR (WinRAR) compatible archiver.
|
||||
The unRAR sources cannot be used to re-create the RAR compression algorithm,
|
||||
which is proprietary. Distribution of modified unRAR sources in separate form
|
||||
or as a part of other software is permitted, provided that it is clearly
|
||||
stated in the documentation and source comments that the code may
|
||||
not be used to develop a RAR (WinRAR) compatible archiver.
|
||||
|
||||
|
||||
--
|
||||
|
||||
340
osx/par2/arm64/LICENSE.txt
Normal file
340
osx/par2/arm64/LICENSE.txt
Normal file
@@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
28
osx/par2/arm64/README.md
Normal file
28
osx/par2/arm64/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Creating `par2` for M1 systems
|
||||
|
||||
Compiled on an M1 system using these steps.
|
||||
|
||||
If you do not use llvm and `clang++` it will not include multithreading support.
|
||||
|
||||
However, I was unable to statically link the `libomp` library inside the `par2` executable.
|
||||
I extracted it from the llvm libs folder and modified `par2` to look for the `libomp.dylib` in the same folder using `install_name_tool`.
|
||||
|
||||
Ref: https://stackoverflow.com/questions/4677044/how-to-use-dylib-in-mac-os-x-c
|
||||
|
||||
```shell
|
||||
brew install automake
|
||||
brew install llvm
|
||||
echo 'export PATH="/opt/homebrew/opt/llvm/bin:$PATH"' >> ~/.zshrc
|
||||
|
||||
# Restart terminal and clone/download par2cmdline sources
|
||||
|
||||
./automake.sh
|
||||
CPPFLAGS="-I/opt/homebrew/opt/llvm/include" LDFLAGS="-L/opt/homebrew/opt/llvm/lib" CXX="clang++" ./configure
|
||||
make clean
|
||||
make
|
||||
make check
|
||||
|
||||
# Do magic to copy and modify the OpenMP library
|
||||
cp /opt/homebrew/opt/llvm/lib/libomp.dylib .
|
||||
install_name_tool -change /opt/homebrew/opt/llvm/lib/libomp.dylib @executable_path/libomp.dylib ./par2
|
||||
```
|
||||
BIN
osx/par2/arm64/libomp.dylib
Executable file
BIN
osx/par2/arm64/libomp.dylib
Executable file
Binary file not shown.
BIN
osx/par2/arm64/par2
Executable file
BIN
osx/par2/arm64/par2
Executable file
Binary file not shown.
BIN
osx/unrar/arm64/unrar
Executable file
BIN
osx/unrar/arm64/unrar
Executable file
Binary file not shown.
BIN
osx/unrar/unrar
BIN
osx/unrar/unrar
Binary file not shown.
@@ -5,7 +5,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: team@sabnzbd.org\n"
|
||||
"Language-Team: SABnzbd <team@sabnzbd.org>\n"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Language-Team: Czech (https://www.transifex.com/sabnzbd/teams/111101/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Danish (https://www.transifex.com/sabnzbd/teams/111101/da/)\n"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: German (https://www.transifex.com/sabnzbd/teams/111101/de/)\n"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Spanish (https://www.transifex.com/sabnzbd/teams/111101/es/)\n"
|
||||
@@ -15,7 +15,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Finnish (https://www.transifex.com/sabnzbd/teams/111101/fi/)\n"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: French (https://www.transifex.com/sabnzbd/teams/111101/fr/)\n"
|
||||
@@ -15,7 +15,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fr\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: ION, 2020\n"
|
||||
"Language-Team: Hebrew (https://www.transifex.com/sabnzbd/teams/111101/he/)\n"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Norwegian Bokmål (https://www.transifex.com/sabnzbd/teams/111101/nb/)\n"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Dutch (https://www.transifex.com/sabnzbd/teams/111101/nl/)\n"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Polish (https://www.transifex.com/sabnzbd/teams/111101/pl/)\n"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Portuguese (Brazil) (https://www.transifex.com/sabnzbd/teams/111101/pt_BR/)\n"
|
||||
@@ -15,7 +15,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: pt_BR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
|
||||
#: email/email.tmpl:1
|
||||
msgid ""
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Romanian (https://www.transifex.com/sabnzbd/teams/111101/ro/)\n"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Russian (https://www.transifex.com/sabnzbd/teams/111101/ru/)\n"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Serbian (https://www.transifex.com/sabnzbd/teams/111101/sr/)\n"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Swedish (https://www.transifex.com/sabnzbd/teams/111101/sv/)\n"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Chinese (China) (https://www.transifex.com/sabnzbd/teams/111101/zh_CN/)\n"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
711
po/main/cs.po
711
po/main/cs.po
File diff suppressed because it is too large
Load Diff
715
po/main/da.po
715
po/main/da.po
File diff suppressed because it is too large
Load Diff
828
po/main/de.po
828
po/main/de.po
File diff suppressed because it is too large
Load Diff
728
po/main/es.po
728
po/main/es.po
File diff suppressed because it is too large
Load Diff
714
po/main/fi.po
714
po/main/fi.po
File diff suppressed because it is too large
Load Diff
756
po/main/fr.po
756
po/main/fr.po
File diff suppressed because it is too large
Load Diff
722
po/main/he.po
722
po/main/he.po
File diff suppressed because it is too large
Load Diff
718
po/main/nb.po
718
po/main/nb.po
File diff suppressed because it is too large
Load Diff
740
po/main/nl.po
740
po/main/nl.po
File diff suppressed because it is too large
Load Diff
715
po/main/pl.po
715
po/main/pl.po
File diff suppressed because it is too large
Load Diff
720
po/main/pt_BR.po
720
po/main/pt_BR.po
File diff suppressed because it is too large
Load Diff
715
po/main/ro.po
715
po/main/ro.po
File diff suppressed because it is too large
Load Diff
711
po/main/ru.po
711
po/main/ru.po
File diff suppressed because it is too large
Load Diff
715
po/main/sr.po
715
po/main/sr.po
File diff suppressed because it is too large
Load Diff
716
po/main/sv.po
716
po/main/sv.po
File diff suppressed because it is too large
Load Diff
709
po/main/zh_CN.po
709
po/main/zh_CN.po
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: team@sabnzbd.org\n"
|
||||
"Language-Team: SABnzbd <team@sabnzbd.org>\n"
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
# Copyright 2007-2022 The SABnzbd-Team
|
||||
# team@sabnzbd.org
|
||||
#
|
||||
# Translators:
|
||||
# Pavel C <quoing_transifex@mess.cz>, 2022
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Pavel C <quoing_transifex@mess.cz>, 2022\n"
|
||||
"Language-Team: Czech (https://www.transifex.com/sabnzbd/teams/111101/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -19,7 +23,7 @@ msgstr ""
|
||||
|
||||
#: builder/win/NSIS_Installer.nsi
|
||||
msgid "Support the project, Donate!"
|
||||
msgstr ""
|
||||
msgstr "Podpořte projekt!"
|
||||
|
||||
#: builder/win/NSIS_Installer.nsi
|
||||
msgid "Please close \"SABnzbd.exe\" first"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Danish (https://www.transifex.com/sabnzbd/teams/111101/da/)\n"
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# SABnzbd Translation Template file NSIS
|
||||
# Copyright 2007-2022 The SABnzbd-Team
|
||||
# team@sabnzbd.org
|
||||
#
|
||||
#
|
||||
# Translators:
|
||||
# Safihre <safihre@sabnzbd.org>, 2020
|
||||
# Simon W., 2021
|
||||
#
|
||||
# reloxx13 <reloxx@interia.pl>, 2022
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Simon W., 2021\n"
|
||||
"Last-Translator: reloxx13 <reloxx@interia.pl>, 2022\n"
|
||||
"Language-Team: German (https://www.transifex.com/sabnzbd/teams/111101/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -44,15 +44,15 @@ msgid ""
|
||||
"The installer only supports 64-bit Windows, use the standalone version to "
|
||||
"run on 32-bit Windows."
|
||||
msgstr ""
|
||||
"Der Installer unterstützt nur Windows 64-bit. Benutze die Standalone Version"
|
||||
" für Windows 32-bit."
|
||||
"Der Installer unterstützt nur Windows 64-Bit. Benutze die Portable Version "
|
||||
"für Windows 32-Bit."
|
||||
|
||||
#: builder/win/NSIS_Installer.nsi
|
||||
msgid ""
|
||||
"The installer only supports Windows 8.1 and above, use the standalone legacy"
|
||||
" version to run on older Windows version."
|
||||
msgstr ""
|
||||
"Der Installer unterstützt nur Windows 8.1 und höher. Benutze die standalone "
|
||||
"Der Installer unterstützt nur Windows 8.1 und höher. Benutze die Standalone-"
|
||||
"Version für ältere Windows Versionen."
|
||||
|
||||
#: builder/win/NSIS_Installer.nsi
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Ester Molla Aragones <moarages@gmail.com>, 2020\n"
|
||||
"Language-Team: Spanish (https://www.transifex.com/sabnzbd/teams/111101/es/)\n"
|
||||
@@ -16,7 +16,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
|
||||
#: builder/win/NSIS_Installer.nsi
|
||||
msgid "Show Release Notes"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-develop\n"
|
||||
"Project-Id-Version: SABnzbd-3.7.0Beta1\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
|
||||
"Language-Team: Finnish (https://www.transifex.com/sabnzbd/teams/111101/fi/)\n"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user