mirror of
https://github.com/sabnzbd/sabnzbd.git
synced 2026-09-08 11:44:34 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
675d7714ca | ||
|
|
bcd1585ea1 | ||
|
|
9d365facaa | ||
|
|
948500799a | ||
|
|
d8815ef983 | ||
|
|
ff537363c6 | ||
|
|
b58a25df07 | ||
|
|
1ce8faafeb | ||
|
|
7dbecb0a2d | ||
|
|
8343f182aa | ||
|
|
d3f691e695 | ||
|
|
d25d857fc4 | ||
|
|
64f342ca1d | ||
|
|
ab3ba4a53a | ||
|
|
169a42b08c | ||
|
|
6cbe811d10 | ||
|
|
33ff6800d2 | ||
|
|
ec61683097 | ||
|
|
069f978e64 | ||
|
|
c65ce5d5aa | ||
|
|
443b34ce55 | ||
|
|
fbe07dfb7e | ||
|
|
168622ea47 | ||
|
|
ab702860df | ||
|
|
4a999a1908 | ||
|
|
975c552a6a | ||
|
|
20915cc626 | ||
|
|
4fde6e490c | ||
|
|
58c3c13954 | ||
|
|
7b3d1d41ab | ||
|
|
cb1102d992 | ||
|
|
ecf5e27c04 | ||
|
|
cd96dadcc3 | ||
|
|
fb2660dbb9 | ||
|
|
f9cb5b302b | ||
|
|
614b3faca6 | ||
|
|
e4162b093a | ||
|
|
e1009e1e92 | ||
|
|
f8781e1e35 | ||
|
|
be5d394ebd | ||
|
|
55285c5cf9 | ||
|
|
c3f6b2d582 | ||
|
|
5088e14fa6 | ||
|
|
139b4a52b6 | ||
|
|
7a852e8654 | ||
|
|
fd9acd2ea8 | ||
|
|
eb673d3956 | ||
|
|
f7513c05b9 | ||
|
|
e3bc15e8e6 | ||
|
|
b263c6cfe6 | ||
|
|
d990a17424 | ||
|
|
38c2a7bca7 | ||
|
|
e2a4d9953b | ||
|
|
5696a667e7 | ||
|
|
0651dd7a3a | ||
|
|
b192a7eca4 | ||
|
|
75f7db398a | ||
|
|
90f092a1a5 | ||
|
|
f498147189 | ||
|
|
e36d989ee5 | ||
|
|
e0acbd75e2 | ||
|
|
2ce13bdd9a | ||
|
|
93546e5b7a | ||
|
|
5973e5b6ed | ||
|
|
0fe92487b6 | ||
|
|
743ff89cff | ||
|
|
43f22b579f | ||
|
|
817ea452ba | ||
|
|
8c21f47f4c | ||
|
|
3813a810ed | ||
|
|
602464349f | ||
|
|
bdd821233f | ||
|
|
611dfa74d2 | ||
|
|
21d639bf5f | ||
|
|
6d897a5f23 | ||
|
|
537ac2e7a4 | ||
|
|
cb2c44cfc2 | ||
|
|
adde7b961c | ||
|
|
9639d651f4 | ||
|
|
f481496e5d | ||
|
|
e0bf9218bb | ||
|
|
19b597d21b | ||
|
|
86a2025eca | ||
|
|
0996998ed9 | ||
|
|
583617f0a9 | ||
|
|
d45a1d8bf0 | ||
|
|
2e99fd6fd0 | ||
|
|
cf26260910 | ||
|
|
59218a687d | ||
|
|
61df709a04 | ||
|
|
1fcada54f9 | ||
|
|
289b91a3de | ||
|
|
35d5355f49 | ||
|
|
ec6ba3baae | ||
|
|
d6474cb695 | ||
|
|
4520de77ad | ||
|
|
ada9d83593 | ||
|
|
58386e0b61 | ||
|
|
4601f4b690 | ||
|
|
fd191d1b79 | ||
|
|
5014673f87 | ||
|
|
14ce150b31 | ||
|
|
8e39722359 | ||
|
|
ba36e62695 | ||
|
|
250a4dbf2a | ||
|
|
3867cefa0a | ||
|
|
d530764a6d | ||
|
|
b5a7385d48 | ||
|
|
40860c68ca | ||
|
|
3213cd74cf | ||
|
|
b8838c4728 | ||
|
|
047ed77dd4 | ||
|
|
78cb553b14 | ||
|
|
c5ebea7bbd | ||
|
|
7b02c74386 | ||
|
|
0c3464e6a2 | ||
|
|
d889d4fd30 | ||
|
|
70f89e98e8 | ||
|
|
2cb12a07c9 | ||
|
|
3d7f5d4289 | ||
|
|
3abf4c7bdb | ||
|
|
947b2b815c | ||
|
|
d167fb0fe7 | ||
|
|
b7da5b6684 | ||
|
|
df9c57f539 | ||
|
|
d5a7f8631c | ||
|
|
dcb618ce99 | ||
|
|
dc5620a52c | ||
|
|
40a3941b9e | ||
|
|
eb9229d326 | ||
|
|
0411e8acc1 | ||
|
|
f405b8927a | ||
|
|
47a507f5a6 | ||
|
|
bdca9715b2 | ||
|
|
0954ac143d | ||
|
|
9122633907 | ||
|
|
1b6aea3afb | ||
|
|
af10190e0b | ||
|
|
1acfc5139c | ||
|
|
404060373b | ||
|
|
a84544bef8 | ||
|
|
f38b602924 | ||
|
|
db57321cb8 | ||
|
|
b825636d3f | ||
|
|
fa3f8735ea | ||
|
|
c359b21d89 | ||
|
|
3ab1782dc2 | ||
|
|
91c228353b | ||
|
|
1336d66f78 | ||
|
|
1f7bec651d | ||
|
|
8f02e59c31 | ||
|
|
efb16cc69b | ||
|
|
f6020aa9f7 | ||
|
|
2d2b88e771 | ||
|
|
6731da2d68 | ||
|
|
cf8ab5a8d5 | ||
|
|
636aa91e21 | ||
|
|
a1c9a8aab1 | ||
|
|
73e7dd8084 | ||
|
|
6eb257388b | ||
|
|
ba2099d006 | ||
|
|
8f044bb19e | ||
|
|
889fbf688d | ||
|
|
ab879cc7d0 | ||
|
|
5b7a89ffb8 | ||
|
|
1eed5c7866 | ||
|
|
44777dc3cf | ||
|
|
c91b53d290 | ||
|
|
ef2ee17c13 | ||
|
|
a2aec15a38 | ||
|
|
73af985e60 | ||
|
|
988955374c | ||
|
|
28eaa6c20d | ||
|
|
5c247e008c | ||
|
|
bf02e9da44 | ||
|
|
fb9dbcf824 | ||
|
|
6a85b2daea | ||
|
|
a2ac2b0435 | ||
|
|
8a92f4ac71 | ||
|
|
2556ef10c2 | ||
|
|
661b4ae535 | ||
|
|
0bcb28d576 | ||
|
|
02ced74783 | ||
|
|
8afb8a91e2 | ||
|
|
dc421047d3 | ||
|
|
7fd2848278 | ||
|
|
ef8df5b578 | ||
|
|
1b4525656f | ||
|
|
fd6d8c71c7 | ||
|
|
2e202eca23 | ||
|
|
6b76603c60 | ||
|
|
e929a0c6b6 | ||
|
|
ee8d9bdcf9 | ||
|
|
d9cd7a72b1 | ||
|
|
6112ded96b | ||
|
|
dbe7cb336d | ||
|
|
376fc8a1bf | ||
|
|
9e09817722 | ||
|
|
6db37d9883 | ||
|
|
2a9e9954a8 | ||
|
|
e3e7fcf361 | ||
|
|
b057bc6afc | ||
|
|
1b368a4278 | ||
|
|
a55251f698 | ||
|
|
196241d2cc | ||
|
|
5b3cf86f68 | ||
|
|
6289b74470 | ||
|
|
e9ff8a1595 | ||
|
|
972f4832c1 | ||
|
|
560e342460 | ||
|
|
7b90868007 | ||
|
|
e21798b163 | ||
|
|
9b33f4ce85 | ||
|
|
7daa0159ec | ||
|
|
f0d3e6b8b9 | ||
|
|
82aa38c087 | ||
|
|
228e7e650e | ||
|
|
89e8788b03 | ||
|
|
3e1812280e | ||
|
|
5d3286654e | ||
|
|
cdb87866ae | ||
|
|
8919aa7ec0 | ||
|
|
4d6df7dd22 | ||
|
|
6f342dade5 | ||
|
|
957d0fcd01 | ||
|
|
662dfb7f21 | ||
|
|
7c08959460 | ||
|
|
fee562d57f | ||
|
|
643e5182f7 | ||
|
|
129aae79a1 | ||
|
|
ca93b63ca8 | ||
|
|
83ac44eabc | ||
|
|
3c922ee087 | ||
|
|
dcfe8b076f | ||
|
|
f1486e2d4b | ||
|
|
aee1cd8e41 | ||
|
|
1ee9f56041 | ||
|
|
777db20158 | ||
|
|
e969276828 | ||
|
|
e3acbdc8c2 | ||
|
|
cc5c0037a5 | ||
|
|
45aafe0774 | ||
|
|
afae687b6a | ||
|
|
740eb442a8 | ||
|
|
a141dc942b | ||
|
|
83d167415a | ||
|
|
5c4d2f1d9f | ||
|
|
09c338dd5b | ||
|
|
bff7d559f9 | ||
|
|
51985d3bf6 | ||
|
|
1f3cd7adbd | ||
|
|
1f9a87e64f | ||
|
|
508ae12c8f | ||
|
|
92489bb624 | ||
|
|
fa982d4f69 | ||
|
|
64f55c0834 | ||
|
|
babd8517e9 | ||
|
|
0950393b82 | ||
|
|
08bcddf8d2 | ||
|
|
eae5f164e6 | ||
|
|
d5700bf8a3 | ||
|
|
d969d3df1a | ||
|
|
5e3126cd14 | ||
|
|
f3ef46e5c2 | ||
|
|
ca5e02f2f1 | ||
|
|
dc870495c5 | ||
|
|
a6491750f7 | ||
|
|
6dacc71cb4 | ||
|
|
23c00b571c | ||
|
|
cc61dc974b | ||
|
|
7f421a3c0b | ||
|
|
2740ad20b6 | ||
|
|
57e371aba5 | ||
|
|
c1096dc0ab | ||
|
|
08bdd12298 | ||
|
|
7b2e139e45 | ||
|
|
1ce1440df8 | ||
|
|
a7c897f2ad | ||
|
|
a344726c68 | ||
|
|
b0c31c7e10 | ||
|
|
2c530fee47 | ||
|
|
25d20f0f08 | ||
|
|
3aaebed274 | ||
|
|
f12725eea5 | ||
|
|
dbf8ef15ef | ||
|
|
de5abc95f5 | ||
|
|
04379e3faa | ||
|
|
fec57377db | ||
|
|
2f4750f77d | ||
|
|
820442bdbd | ||
|
|
e63648c9c4 | ||
|
|
a8751c5e77 | ||
|
|
196a92550c | ||
|
|
526fcd3544 | ||
|
|
f817e4f0fb | ||
|
|
d7ca91e395 | ||
|
|
e3c8d79dae | ||
|
|
2cb472f690 | ||
|
|
caee1d3bfe | ||
|
|
8069361faa | ||
|
|
02c567fd8c | ||
|
|
60f555117c | ||
|
|
f259e47110 | ||
|
|
10ffcb2c82 | ||
|
|
1564ee3ccf | ||
|
|
b6b992e521 | ||
|
|
290f85ca1c | ||
|
|
80840ce743 | ||
|
|
0434dca45f | ||
|
|
81bc2a384f | ||
|
|
2184964d78 | ||
|
|
b942e06297 | ||
|
|
5598db0d9e | ||
|
|
f7ad95f298 | ||
|
|
61e30ab419 | ||
|
|
90798e5e4d | ||
|
|
8be8af018f | ||
|
|
7abb39d02d | ||
|
|
2668f1cd26 | ||
|
|
2a28a00c19 | ||
|
|
9d7ab53685 | ||
|
|
95f3b9fcc1 | ||
|
|
ae170c6879 | ||
|
|
0831f0c202 | ||
|
|
fc214a7ef9 | ||
|
|
cb0bb885c4 | ||
|
|
053c51bb58 | ||
|
|
c1860aa4c4 | ||
|
|
4d14d663b3 | ||
|
|
ee3cd747b9 | ||
|
|
5f933ddc21 | ||
|
|
98dc183881 | ||
|
|
791650960b | ||
|
|
e8fef31a3e | ||
|
|
d48a2f89c6 | ||
|
|
d8e572f091 | ||
|
|
51ea306d9f | ||
|
|
4ded1e242e | ||
|
|
7bdfb54bee | ||
|
|
96975050b5 | ||
|
|
b84fd1526a | ||
|
|
0ec9194d78 | ||
|
|
2cb598309d | ||
|
|
1d91b9acf3 | ||
|
|
c776f086cd | ||
|
|
8d83240b1a | ||
|
|
f1f9be77d7 | ||
|
|
e5eb66bc7b | ||
|
|
5ef63fd414 | ||
|
|
29c3513cd4 | ||
|
|
d45295e4ee | ||
|
|
395f8dc4c5 | ||
|
|
375cc4955d | ||
|
|
6ff8aa7cef | ||
|
|
0117941422 | ||
|
|
004e4e68eb | ||
|
|
a72bb62a9d |
No files matched your search
@@ -4,6 +4,7 @@ description: >
|
||||
If you are not 100% certain this is a bug please go to our forums, Reddit or Discord server first.
|
||||
labels:
|
||||
- Support
|
||||
type: bug
|
||||
body:
|
||||
- type: input
|
||||
attributes:
|
||||
|
||||
@@ -2,6 +2,7 @@ name: Feature request
|
||||
description: What new feature would you like to have added to SABnzbd?
|
||||
labels:
|
||||
- Support
|
||||
type: feature
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
||||
+26
-2
@@ -7,6 +7,7 @@
|
||||
"schedule": [
|
||||
"before 8am on Monday"
|
||||
],
|
||||
"minimumReleaseAge": "14 days",
|
||||
"baseBranches": ["develop"],
|
||||
"pip_requirements": {
|
||||
"fileMatch": [
|
||||
@@ -16,13 +17,36 @@
|
||||
"builder/release-requirements.txt"
|
||||
]
|
||||
},
|
||||
"customManagers": [
|
||||
{
|
||||
"customType": "regex",
|
||||
"fileMatch": ["^\\.github/workflows/build_release\\.yml$"],
|
||||
"matchStrings": ["PYTHON_VERSION:\\s*\"(?<currentValue>.*?)\""],
|
||||
"datasourceTemplate": "python-version",
|
||||
"depNameTemplate": "python"
|
||||
},
|
||||
{
|
||||
"customType": "regex",
|
||||
"fileMatch": ["^sabnzbd/constants\\.py$"],
|
||||
"matchStrings": ["SABCTOOLS_VERSION_REQUIRED\\s*=\\s*\"(?<currentValue>.*?)\""],
|
||||
"datasourceTemplate": "pypi",
|
||||
"depNameTemplate": "sabctools"
|
||||
},
|
||||
{
|
||||
"customType": "regex",
|
||||
"fileMatch": ["^\\.github/workflows/translations\\.yml$"],
|
||||
"matchStrings": ["TX_VERSION=\"(?<currentValue>.*?)\""],
|
||||
"datasourceTemplate": "github-releases",
|
||||
"depNameTemplate": "transifex/cli"
|
||||
}
|
||||
],
|
||||
"ignorePaths": [],
|
||||
"ignoreDeps": [
|
||||
"jaraco.text",
|
||||
"jaraco.context",
|
||||
"jaraco.collections",
|
||||
"sabctools",
|
||||
"paho-mqtt"
|
||||
"tempora",
|
||||
"cryptography"
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
|
||||
@@ -2,9 +2,16 @@ name: Build binaries and source distribution
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
# Setting PYTHONNODEBUGRANGES reduces binary size
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
# Setting PYTHONNODEBUGRANGES reduces binary size
|
||||
PYTHONNODEBUGRANGES: 1
|
||||
# For macOS we download the official Python, because the GitHub one only support newer macOS 11+ versions
|
||||
# We also use the specific pin for Windows release, so Renovate can update it all at once
|
||||
PYTHON_VERSION: "3.14.7"
|
||||
|
||||
jobs:
|
||||
build_windows:
|
||||
@@ -22,11 +29,11 @@ jobs:
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: "3.14"
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
architecture: ${{ matrix.architecture }}
|
||||
cache: pip
|
||||
cache-dependency-path: "**/requirements.txt"
|
||||
@@ -34,19 +41,21 @@ jobs:
|
||||
# Without dependencies to make sure everything is covered in the requirements.txt
|
||||
# Special settings:
|
||||
# cryptography see https://github.com/pyca/cryptography/pull/14216
|
||||
# charset-normalizer see https://github.com/jawah/charset_normalizer/issues/714
|
||||
run: |
|
||||
python --version
|
||||
python -m pip install --upgrade pip wheel
|
||||
pip install --upgrade -r requirements.txt --no-dependencies --only-binary=cryptography --no-binary charset-normalizer
|
||||
pip install --upgrade -r builder/requirements.txt --no-dependencies
|
||||
pip install -r requirements.txt --no-dependencies --only-binary=cryptography
|
||||
pip install -r builder/requirements.txt --no-dependencies
|
||||
- name: Build Windows standalone binary
|
||||
id: windows_binary
|
||||
run: python builder/package.py binary
|
||||
- name: Upload Windows standalone binary (unsigned)
|
||||
# When releasing, SignPath consumes this artifact directly and requires the
|
||||
# zip-in-zip layout because they don't support the archive-flag
|
||||
uses: actions/upload-artifact@v7
|
||||
id: upload-unsigned-binary
|
||||
with:
|
||||
archive: ${{ contains(github.ref, 'refs/tags/') }}
|
||||
path: "*-win*-bin.zip"
|
||||
name: Windows standalone binary (${{ matrix.architecture }})
|
||||
- name: Sign Windows standalone binary
|
||||
@@ -62,11 +71,13 @@ jobs:
|
||||
wait-for-completion: true
|
||||
output-artifact-directory: "signed"
|
||||
- name: Upload Windows standalone binary (signed)
|
||||
# The release file is a .zip, which download-artifact would extract if
|
||||
# uploaded raw, so keep it archived and let the release job unpack it
|
||||
uses: actions/upload-artifact@v7
|
||||
if: contains(github.ref, 'refs/tags/')
|
||||
with:
|
||||
name: Windows standalone binary (${{ matrix.architecture }}, signed)
|
||||
path: "signed"
|
||||
path: "signed/*-win*-bin.zip"
|
||||
- name: Build Windows installer
|
||||
if: matrix.architecture == 'x64'
|
||||
run: python builder/package.py installer
|
||||
@@ -75,6 +86,7 @@ jobs:
|
||||
uses: actions/upload-artifact@v7
|
||||
id: upload-unsigned-installer
|
||||
with:
|
||||
archive: ${{ contains(github.ref, 'refs/tags/') }}
|
||||
path: "*-win-setup.exe"
|
||||
name: Windows installer (${{ matrix.architecture }})
|
||||
- name: Sign Windows installer
|
||||
@@ -93,7 +105,7 @@ jobs:
|
||||
if: matrix.architecture == 'x64' && contains(github.ref, 'refs/tags/')
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: Windows installer (${{ matrix.architecture }}, signed)
|
||||
archive: false
|
||||
path: "signed/*-win-setup.exe"
|
||||
|
||||
build_macos:
|
||||
@@ -101,26 +113,24 @@ jobs:
|
||||
runs-on: macos-14
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
# We need the official Python, because the GA ones only support newer macOS versions
|
||||
# The deployment target is picked up by the Python build tools automatically
|
||||
# If updated, make sure to also set LSMinimumSystemVersion in SABnzbd.spec
|
||||
PYTHON_VERSION: "3.14.3"
|
||||
MACOSX_DEPLOYMENT_TARGET: "10.15"
|
||||
# We need to force compile for universal2 support
|
||||
CFLAGS: -arch x86_64 -arch arm64
|
||||
ARCHFLAGS: -arch x86_64 -arch arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- name: Set up Python
|
||||
# Only use this for the caching of pip packages!
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: "3.14"
|
||||
cache: pip
|
||||
cache-dependency-path: "**/requirements.txt"
|
||||
- name: Cache Python download
|
||||
id: cache-python-download
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/python.pkg
|
||||
key: cache-macOS-Python-${{ env.PYTHON_VERSION }}
|
||||
@@ -134,8 +144,8 @@ jobs:
|
||||
run: |
|
||||
python3 --version
|
||||
pip3 install --upgrade pip wheel
|
||||
pip3 install --upgrade -r requirements.txt --no-binary cffi,CT3,PyYAML,charset_normalizer --no-dependencies
|
||||
pip3 install --upgrade -r builder/requirements.txt --no-dependencies
|
||||
pip3 install -r requirements.txt --no-binary cffi,CT3,PyYAML,httptools --no-dependencies
|
||||
pip3 install -r builder/requirements.txt --no-dependencies
|
||||
- name: Import macOS codesign certificates
|
||||
# Taken from https://github.com/Apple-Actions/import-codesign-certs/pull/27 (comments)
|
||||
env:
|
||||
@@ -157,8 +167,8 @@ jobs:
|
||||
- name: Upload source distribution
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
archive: false
|
||||
path: "*-src.tar.gz"
|
||||
name: Source distribution
|
||||
- name: Build macOS binary
|
||||
env:
|
||||
SIGNING_AUTH: ${{ secrets.SIGNING_AUTH }}
|
||||
@@ -169,100 +179,44 @@ jobs:
|
||||
- name: Upload macOS binary
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
archive: false
|
||||
path: "*-macos.dmg"
|
||||
name: macOS binary
|
||||
|
||||
build-snap:
|
||||
name: Build Snap Packages (${{ matrix.linux_arch }})
|
||||
timeout-minutes: 30
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
linux_arch: x64
|
||||
- os: ubuntu-24.04-arm
|
||||
linux_arch: arm64
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Cache par2cmdline-turbo tarball
|
||||
uses: actions/cache@v5
|
||||
id: cache-par2cmdline
|
||||
# Clearing the cache in case of new version requires manual clearing in GitHub!
|
||||
with:
|
||||
path: snap/par2cmdline.tar.gz
|
||||
key: cache-par2cmdline
|
||||
- name: Download par2cmdline-turbo tarball
|
||||
if: steps.cache-par2cmdline.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
PAR2_TARBALL=$(curl -sL https://api.github.com/repos/animetosho/par2cmdline-turbo/releases/latest | jq -r '.tarball_url')
|
||||
curl -o snap/par2cmdline.tar.gz -L "$PAR2_TARBALL"
|
||||
- uses: snapcore/action-build@v1
|
||||
name: Build snap
|
||||
id: snapcraft
|
||||
- name: Test snap installation
|
||||
run: |
|
||||
sudo snap install --dangerous *.snap
|
||||
sudo snap connect sabnzbd:removable-media
|
||||
# Basic smoke test - check that the binary exists and can show help
|
||||
timeout 10s snap run sabnzbd --help || true
|
||||
sudo snap remove sabnzbd
|
||||
- name: Upload snap
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: Snap package (${{ matrix.linux_arch }})
|
||||
path: ${{ steps.snapcraft.outputs.snap }}
|
||||
- name: Determine snap channel
|
||||
if: contains(github.ref, 'refs/tags/')
|
||||
id: snap-channel
|
||||
run: |
|
||||
TAG="${GITHUB_REF#refs/tags/}"
|
||||
if [[ "$TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "channel=stable,beta" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "channel=beta" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Publish snap
|
||||
uses: snapcore/action-publish@v1
|
||||
if: contains(github.ref, 'refs/tags/')
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_TOKEN }}
|
||||
with:
|
||||
store_login: ${{ secrets.SNAP_TOKEN }}
|
||||
snap: ${{ steps.snapcraft.outputs.snap }}
|
||||
release: ${{ steps.snap-channel.outputs.channel }}
|
||||
|
||||
release:
|
||||
name: Prepare Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_windows, build_macos]
|
||||
if: contains(github.ref, 'refs/tags/')
|
||||
environment: release
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: "3.14"
|
||||
cache: pip
|
||||
cache-dependency-path: "builder/release-requirements.txt"
|
||||
- name: Download Source distribution artifact
|
||||
- name: Download release artifacts
|
||||
# The installer, source and macOS builds are uploaded with archive: false,
|
||||
# so their artifact name is the release filename
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: Source distribution
|
||||
- name: Download macOS artifact
|
||||
pattern: "SABnzbd-*"
|
||||
merge-multiple: true
|
||||
- name: Download signed Windows binaries
|
||||
# These stay archived (.zip release files), so download-artifact unpacks
|
||||
# them back into the release .zip
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: macOS binary
|
||||
- name: Download Windows artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: ${{ (contains(github.ref, 'refs/tags/')) && '*signed*' || '*Windows*' }}
|
||||
pattern: "*signed*"
|
||||
merge-multiple: true
|
||||
- name: Prepare official release
|
||||
env:
|
||||
AUTOMATION_GITHUB_TOKEN: ${{ secrets.AUTOMATION_GITHUB_TOKEN }}
|
||||
REDDIT_TOKEN: ${{ secrets.REDDIT_TOKEN }}
|
||||
LINUXSERVER_WEBHOOK_TOKEN: ${{ secrets.LINUXSERVER_WEBHOOK_TOKEN }}
|
||||
DISCORD_WEBHOOK_TESTING: ${{ secrets.DISCORD_WEBHOOK_TESTING }}
|
||||
DISCORD_WEBHOOK_STABLE: ${{ secrets.DISCORD_WEBHOOK_STABLE }}
|
||||
run: |
|
||||
pip3 install -r builder/release-requirements.txt
|
||||
pip3 install -r builder/release-requirements.txt --no-dependencies
|
||||
python3 builder/release.py
|
||||
@@ -0,0 +1,91 @@
|
||||
name: Build and publish Snap packages
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'snap/**'
|
||||
- 'requirements.txt'
|
||||
- '.github/workflows/build_snaps.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'snap/**'
|
||||
- 'requirements.txt'
|
||||
- '.github/workflows/build_snaps.yml'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-snap:
|
||||
name: Build Snap Packages (${{ matrix.linux_arch }})
|
||||
timeout-minutes: 30
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
linux_arch: x64
|
||||
- os: ubuntu-24.04-arm
|
||||
linux_arch: arm64
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- name: Cache par2cmdline-turbo tarball
|
||||
uses: actions/cache@v6
|
||||
id: cache-par2cmdline
|
||||
# Clearing the cache in case of new version requires manual clearing in GitHub!
|
||||
with:
|
||||
path: snap/par2cmdline.tar.gz
|
||||
key: cache-par2cmdline
|
||||
- name: Download par2cmdline-turbo tarball
|
||||
if: steps.cache-par2cmdline.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
PAR2_TARBALL=$(curl -sL https://api.github.com/repos/animetosho/par2cmdline-turbo/releases/latest | jq -r '.tarball_url')
|
||||
curl -o snap/par2cmdline.tar.gz -L "$PAR2_TARBALL"
|
||||
- uses: snapcore/action-build@v1
|
||||
name: Build snap
|
||||
id: snapcraft
|
||||
- name: Test snap installation
|
||||
run: |
|
||||
sudo snap install --dangerous *.snap
|
||||
sudo snap connect sabnzbd:removable-media
|
||||
# Installing a daemon snap starts the service automatically.
|
||||
if ! curl -fsSL -o /dev/null \
|
||||
--retry 30 --retry-delay 2 --retry-connrefused --retry-all-errors \
|
||||
http://127.0.0.1:8080/; then
|
||||
echo "::error::SABnzbd web UI did not come up"
|
||||
sudo snap logs sabnzbd -n 200 || true
|
||||
systemctl status snap.sabnzbd.sabnzbd.service --no-pager || true
|
||||
exit 1
|
||||
fi
|
||||
echo "SABnzbd web UI responded"
|
||||
sudo snap remove sabnzbd
|
||||
- name: Upload snap
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: Snap package (${{ matrix.linux_arch }})
|
||||
path: ${{ steps.snapcraft.outputs.snap }}
|
||||
- name: Determine snap channel
|
||||
if: contains(github.ref, 'refs/tags/')
|
||||
id: snap-channel
|
||||
run: |
|
||||
TAG="${GITHUB_REF#refs/tags/}"
|
||||
if [[ "$TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "channel=stable,beta" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "channel=beta" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Publish snap
|
||||
uses: snapcore/action-publish@v1
|
||||
if: contains(github.ref, 'refs/tags/')
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_TOKEN }}
|
||||
with:
|
||||
store_login: ${{ secrets.SNAP_TOKEN }}
|
||||
snap: ${{ steps.snapcraft.outputs.snap }}
|
||||
release: ${{ steps.snap-channel.outputs.channel }}
|
||||
@@ -0,0 +1,32 @@
|
||||
name: "Claude Review (manual)"
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: read
|
||||
|
||||
jobs:
|
||||
review:
|
||||
name: "Review PR on @claude mention"
|
||||
# Only PR comments containing @claude, and only from maintainers
|
||||
if: >
|
||||
github.repository_owner == 'sabnzbd' &&
|
||||
github.event.issue.pull_request &&
|
||||
contains(github.event.comment.body, '@claude') &&
|
||||
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
# Full history so the review can diff the PR against its base branch
|
||||
fetch-depth: 0
|
||||
- uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Actual triggering is gated by the job-level `if` above; this disables
|
||||
# the action's internal write-permission check, which contributors fail
|
||||
allowed_non_write_users: "*"
|
||||
@@ -2,15 +2,22 @@ name: CI Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
black:
|
||||
name: Black Code Formatter
|
||||
black-and-ruff:
|
||||
name: Black and Ruff checks
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- run: pip install black
|
||||
# Tools folder excluded for now due to https://github.com/psf/black/issues/4963
|
||||
- run: >
|
||||
- uses: actions/checkout@v7
|
||||
- run: pip install ruff black
|
||||
- name: Black code formatter
|
||||
run: >
|
||||
black
|
||||
SABnzbd.py
|
||||
sabnzbd
|
||||
@@ -18,9 +25,11 @@ jobs:
|
||||
builder
|
||||
builder/SABnzbd.spec
|
||||
tests
|
||||
--line-length=120
|
||||
tools
|
||||
--check
|
||||
--diff
|
||||
- name: Ruff checks
|
||||
run: ruff check
|
||||
|
||||
test:
|
||||
name: Test ${{ matrix.name }} - Python ${{ matrix.python-version }}
|
||||
@@ -29,7 +38,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13", "3.14" ]
|
||||
# TODO: Remove libxml2-dev libxslt-dev below once 3.15 is stable and lxml releases wheels!
|
||||
python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14", "3.15-dev" ]
|
||||
name: ["Linux"]
|
||||
os: [ubuntu-latest]
|
||||
include:
|
||||
@@ -41,21 +51,23 @@ jobs:
|
||||
python-version: "3.14"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache: pip
|
||||
cache-dependency-path: "**/requirements.txt"
|
||||
- name: Install system dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt-get install unrar 7zip par2
|
||||
run: sudo apt-get install unrar 7zip par2 libxml2-dev libxslt-dev
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python --version
|
||||
python -m pip install --upgrade pip wheel
|
||||
pip install --upgrade -r requirements.txt --no-dependencies
|
||||
pip install -r requirements.txt --no-dependencies
|
||||
pip install --upgrade -r tests/requirements.txt
|
||||
- name: Install Playwright browser
|
||||
run: python -m playwright install chromium --with-deps
|
||||
- name: Test SABnzbd
|
||||
run: pytest -s
|
||||
run: pytest -n auto --dist loadscope
|
||||
@@ -4,13 +4,17 @@ on:
|
||||
- cron: "30 1 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
name: "Close stale issues"
|
||||
if: github.repository_owner == 'sabnzbd'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v10
|
||||
- uses: actions/stale@v11
|
||||
with:
|
||||
days-before-stale: 21
|
||||
days-before-close: 7
|
||||
@@ -19,7 +23,7 @@ jobs:
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
exempt-issue-labels: "Feature request, Work in progress, Bug"
|
||||
only-issue-labels: "Support"
|
||||
|
||||
lock:
|
||||
name: "Lock old issues"
|
||||
|
||||
@@ -5,39 +5,54 @@ on:
|
||||
branches:
|
||||
- develop
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
translations:
|
||||
name: Update translatable texts
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
TX_TOKEN: ${{ secrets.TX_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
token: ${{ secrets.AUTOMATION_GITHUB_TOKEN }}
|
||||
# Need the parent commit too so we can diff HEAD and detect local translation edits
|
||||
fetch-depth: 2
|
||||
- name: Generate translatable texts
|
||||
run: |
|
||||
python3 tools/extract_pot.py
|
||||
- name: Push/pull Transifex translations
|
||||
if: env.TX_TOKEN
|
||||
# Add --translation to the push command in order to update Transifex using local translation edits
|
||||
# However, this prevents modifying existing translations in Transifex as they will be overwritten by the push!
|
||||
# We use fixed version and manual download (instead of their sh script) to prevent potential supply-chain attack.
|
||||
# Changes are commited directly to the repo, so this is quite sensative and worth the extra hassle!
|
||||
# When the current commit contains local translation edits (changes to po/**/*.po), we add --translation so
|
||||
# those edits are pushed to Transifex. Note: this overwrites the matching translations in Transifex with our
|
||||
# local versions, so we only do it when local .po files actually changed.
|
||||
run: |
|
||||
curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash
|
||||
./tx push --source
|
||||
TX_VERSION="v1.6.17"
|
||||
curl -fsSL "https://github.com/transifex/cli/releases/download/${TX_VERSION}/tx-linux-amd64.tar.gz" -o tx-linux-amd64.tar.gz
|
||||
tar -xzf tx-linux-amd64.tar.gz
|
||||
PUSH_ARGS="--source"
|
||||
if git show --name-only --format= HEAD | grep -qE '^po/.+\.po$'; then
|
||||
echo "Local translation edits detected; also pushing translations to Transifex."
|
||||
PUSH_ARGS="--source --translation"
|
||||
fi
|
||||
./tx push ${PUSH_ARGS}
|
||||
./tx pull --all --force
|
||||
- name: Compile translations to validate them
|
||||
run: |
|
||||
python3 tools/make_mo.py
|
||||
- name: Push translatable and translated texts back to repo
|
||||
uses: stefanzweifel/git-auto-commit-action@v7.1.0
|
||||
if: env.TX_TOKEN
|
||||
with:
|
||||
commit_message: |
|
||||
Update translatable texts
|
||||
[skip ci]
|
||||
commit_user_name: SABnzbd Automation
|
||||
commit_user_email: bugs@sabnzbd.org
|
||||
commit_author: SABnzbd Automation <bugs@sabnzbd.org>
|
||||
file_pattern: "po/*.pot po/*.po *.nsi"
|
||||
push_options: --force
|
||||
run: |
|
||||
git config user.name "SABnzbd Automation"
|
||||
git config user.email "bugs@sabnzbd.org"
|
||||
git add po/*.pot po/*.po *.nsi
|
||||
git diff --cached --quiet || git commit -m "Update translatable texts" -m "[skip ci]"
|
||||
git push
|
||||
@@ -0,0 +1,201 @@
|
||||
name: Update bundled tools
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Nightly check for new releases of the bundled tools
|
||||
- cron: "30 4 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
unrar:
|
||||
name: Update unrar
|
||||
if: github.repository == 'sabnzbd/sabnzbd'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.AUTOMATION_GITHUB_TOKEN }}
|
||||
BRANCH: automation/update-unrar
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- name: Determine latest unrar version
|
||||
id: version
|
||||
run: |
|
||||
RAW_VERSION=$(curl -fsSL --retry 3 https://www.rarlab.com/download.htm -o- | sed -n 's%.*/rarmacos-x64-\([0-9]\+\)\.tar\.gz.*%\1%p' | head -1)
|
||||
if [ -z "$RAW_VERSION" ]; then
|
||||
echo "Could not determine the latest unrar version from the rarlab download page"
|
||||
exit 1
|
||||
fi
|
||||
# Version is encoded without separator, e.g. 723 = 7.23
|
||||
VERSION="${RAW_VERSION%??}.${RAW_VERSION: -2}"
|
||||
echo "Latest unrar version: $VERSION"
|
||||
echo "raw_version=$RAW_VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
- name: Download and extract new binaries
|
||||
env:
|
||||
RAW_VERSION: ${{ steps.version.outputs.raw_version }}
|
||||
run: |
|
||||
mkdir -p "$RUNNER_TEMP/unrar"
|
||||
cd "$RUNNER_TEMP/unrar"
|
||||
for FILE in "rarmacos-x64-$RAW_VERSION.tar.gz" "rarmacos-arm-$RAW_VERSION.tar.gz" "winrar-x64-$RAW_VERSION.exe"; do
|
||||
curl -fsSL --retry 3 -o "$FILE" "https://www.rarlab.com/rar/$FILE"
|
||||
done
|
||||
mkdir macos-x64 macos-arm64 windows
|
||||
tar -xzf "rarmacos-x64-$RAW_VERSION.tar.gz" -C macos-x64
|
||||
tar -xzf "rarmacos-arm-$RAW_VERSION.tar.gz" -C macos-arm64
|
||||
# Unpack UnRAR.exe from the WinRAR installer, which is a self-extracting
|
||||
# RAR archive that the preinstalled 7-Zip can read
|
||||
7z x -y -owindows "winrar-x64-$RAW_VERSION.exe" UnRAR.exe > /dev/null
|
||||
- name: Copy binaries into the repository
|
||||
run: |
|
||||
install -m 755 "$RUNNER_TEMP/unrar/macos-x64/rar/unrar" macos/unrar/unrar
|
||||
install -m 755 "$RUNNER_TEMP/unrar/macos-arm64/rar/unrar" macos/unrar/arm64/unrar
|
||||
install -m 755 "$RUNNER_TEMP/unrar/windows/UnRAR.exe" win/unrar/UnRAR.exe
|
||||
- name: Create pull request
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
if git diff --quiet; then
|
||||
echo "Bundled unrar is already at version $VERSION"
|
||||
exit 0
|
||||
fi
|
||||
git config user.name "SABnzbd Automation"
|
||||
git config user.email "bugs@sabnzbd.org"
|
||||
git add macos/unrar win/unrar
|
||||
git commit -m "unrar $VERSION"
|
||||
# Skip the push if an open PR already contains these exact binaries
|
||||
OPEN_PRS=$(gh pr list --head "$BRANCH" --state open --json number --jq length)
|
||||
if [ "$OPEN_PRS" != "0" ] && git fetch origin "$BRANCH" && git diff --quiet FETCH_HEAD HEAD -- macos/unrar win/unrar; then
|
||||
echo "Existing pull request already updates unrar to $VERSION"
|
||||
exit 0
|
||||
fi
|
||||
git push --force origin "HEAD:refs/heads/$BRANCH"
|
||||
if [ "$OPEN_PRS" = "0" ]; then
|
||||
gh pr create --head "$BRANCH" --title "unrar $VERSION" --body "Automated update of the bundled unrar binaries to version $VERSION.
|
||||
|
||||
[Changelog](https://www.rarlab.com/rarnew.htm)"
|
||||
fi
|
||||
|
||||
sevenzip:
|
||||
name: Update 7-Zip
|
||||
if: github.repository == 'sabnzbd/sabnzbd'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.AUTOMATION_GITHUB_TOKEN }}
|
||||
BRANCH: automation/update-7zip
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- name: Determine latest 7-Zip version
|
||||
id: version
|
||||
run: |
|
||||
VERSION=$(gh api repos/ip7z/7zip/releases/latest --jq .tag_name)
|
||||
# Assets are named without separator, e.g. 7z2602-extra.7z for 26.02
|
||||
RAW_VERSION="${VERSION//./}"
|
||||
echo "Latest 7-Zip version: $VERSION"
|
||||
echo "raw_version=$RAW_VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
- name: Download and extract new binaries
|
||||
env:
|
||||
RAW_VERSION: ${{ steps.version.outputs.raw_version }}
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
mkdir -p "$RUNNER_TEMP/7zip"
|
||||
cd "$RUNNER_TEMP/7zip"
|
||||
gh release download "$VERSION" --repo ip7z/7zip \
|
||||
--pattern "7z$RAW_VERSION-extra.7z" --pattern "7z$RAW_VERSION-mac.tar.xz"
|
||||
mkdir macos windows
|
||||
tar -xJf "7z$RAW_VERSION-mac.tar.xz" -C macos
|
||||
# The preinstalled 7-Zip unpacks the extra package that contains
|
||||
# the standalone Windows console version
|
||||
7z x -y -owindows "7z$RAW_VERSION-extra.7z" 7za.exe > /dev/null
|
||||
- name: Copy binaries into the repository
|
||||
run: |
|
||||
install -m 644 "$RUNNER_TEMP/7zip/windows/7za.exe" win/7zip/7za.exe
|
||||
install -m 755 "$RUNNER_TEMP/7zip/macos/7zz" macos/7zip/7zz
|
||||
- name: Create pull request
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
if git diff --quiet; then
|
||||
echo "Bundled 7-Zip is already at version $VERSION"
|
||||
exit 0
|
||||
fi
|
||||
git config user.name "SABnzbd Automation"
|
||||
git config user.email "bugs@sabnzbd.org"
|
||||
git add macos/7zip win/7zip
|
||||
git commit -m "7-Zip $VERSION"
|
||||
# Skip the push if an open PR already contains these exact binaries
|
||||
OPEN_PRS=$(gh pr list --head "$BRANCH" --state open --json number --jq length)
|
||||
if [ "$OPEN_PRS" != "0" ] && git fetch origin "$BRANCH" && git diff --quiet FETCH_HEAD HEAD -- macos/7zip win/7zip; then
|
||||
echo "Existing pull request already updates 7-Zip to $VERSION"
|
||||
exit 0
|
||||
fi
|
||||
git push --force origin "HEAD:refs/heads/$BRANCH"
|
||||
if [ "$OPEN_PRS" = "0" ]; then
|
||||
gh pr create --head "$BRANCH" --title "7-Zip $VERSION" --body "Automated update of the bundled 7-Zip binaries to version $VERSION.
|
||||
|
||||
[Release notes](https://github.com/ip7z/7zip/releases/tag/$VERSION)"
|
||||
fi
|
||||
|
||||
par2:
|
||||
name: Update par2cmdline-turbo
|
||||
if: github.repository == 'sabnzbd/sabnzbd'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.AUTOMATION_GITHUB_TOKEN }}
|
||||
BRANCH: automation/update-par2
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- name: Determine latest par2cmdline-turbo version
|
||||
id: version
|
||||
run: |
|
||||
TAG=$(gh api repos/animetosho/par2cmdline-turbo/releases/latest --jq .tag_name)
|
||||
# Assets are named without the leading v, e.g. par2cmdline-turbo-1.4.0-win-x64.zip for tag v1.4.0
|
||||
VERSION="${TAG#v}"
|
||||
echo "Latest par2cmdline-turbo version: $VERSION"
|
||||
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
- name: Download and extract new binaries
|
||||
env:
|
||||
TAG: ${{ steps.version.outputs.tag }}
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
mkdir -p "$RUNNER_TEMP/par2"
|
||||
cd "$RUNNER_TEMP/par2"
|
||||
for ARCH in win-x64 win-arm64 macos-universal; do
|
||||
gh release download "$TAG" --repo animetosho/par2cmdline-turbo \
|
||||
--pattern "par2cmdline-turbo-$VERSION-$ARCH.zip"
|
||||
unzip -q -d "$ARCH" "par2cmdline-turbo-$VERSION-$ARCH.zip"
|
||||
done
|
||||
- name: Copy binaries into the repository
|
||||
run: |
|
||||
install -m 644 "$RUNNER_TEMP/par2/win-x64/par2.exe" win/par2/par2.exe
|
||||
install -m 644 "$RUNNER_TEMP/par2/win-arm64/par2.exe" win/par2/arm64/par2.exe
|
||||
install -m 755 "$RUNNER_TEMP/par2/macos-universal/par2" macos/par2/par2
|
||||
- name: Create pull request
|
||||
env:
|
||||
TAG: ${{ steps.version.outputs.tag }}
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
if git diff --quiet; then
|
||||
echo "Bundled par2cmdline-turbo is already at version $VERSION"
|
||||
exit 0
|
||||
fi
|
||||
git config user.name "SABnzbd Automation"
|
||||
git config user.email "bugs@sabnzbd.org"
|
||||
git add macos/par2 win/par2
|
||||
git commit -m "par2cmdline-turbo $VERSION"
|
||||
# Skip the push if an open PR already contains these exact binaries
|
||||
OPEN_PRS=$(gh pr list --head "$BRANCH" --state open --json number --jq length)
|
||||
if [ "$OPEN_PRS" != "0" ] && git fetch origin "$BRANCH" && git diff --quiet FETCH_HEAD HEAD -- macos/par2 win/par2; then
|
||||
echo "Existing pull request already updates par2cmdline-turbo to $VERSION"
|
||||
exit 0
|
||||
fi
|
||||
git push --force origin "HEAD:refs/heads/$BRANCH"
|
||||
if [ "$OPEN_PRS" = "0" ]; then
|
||||
gh pr create --head "$BRANCH" --title "par2cmdline-turbo $VERSION" --body "Automated update of the bundled par2cmdline-turbo binaries to version $VERSION.
|
||||
|
||||
[Release notes](https://github.com/animetosho/par2cmdline-turbo/releases/tag/$TAG)"
|
||||
fi
|
||||
+5
-13
@@ -29,28 +29,20 @@ SABnzbd-*/
|
||||
|
||||
# WingIDE/PyCharm project files
|
||||
*.wp[ru]
|
||||
.idea
|
||||
|
||||
# VScode
|
||||
.vscode/
|
||||
|
||||
# Testing folders
|
||||
.cache
|
||||
.xprocess
|
||||
.pytest*
|
||||
tests/cache
|
||||
tests/cache_gw*
|
||||
|
||||
# General junk
|
||||
*.keep
|
||||
*.bak
|
||||
*.log
|
||||
|
||||
# Some people use Emacs as an editor
|
||||
\#*
|
||||
.\#*
|
||||
|
||||
# AI tools
|
||||
.claude/
|
||||
# Ignore all hidden directories at repo root, except used ones
|
||||
.*/
|
||||
!.github/
|
||||
!.tx/
|
||||
|
||||
# Apple
|
||||
.DS_Store
|
||||
+4
-17
@@ -5,6 +5,7 @@ The SABnzbd-Team is:
|
||||
|
||||
Active team:
|
||||
Safihre
|
||||
mnightingale
|
||||
sanderjo
|
||||
jcfp
|
||||
inpheaux
|
||||
@@ -17,21 +18,8 @@ Sleeping members:
|
||||
Honorary member (and original author):
|
||||
Gregor Kaufmann
|
||||
|
||||
The main contributors and moderators of the translations:
|
||||
Danish: Rene (nordjyden6), Scott
|
||||
Dutch: ShyPike, Safihre
|
||||
French: rAf, Fox Ace, Fred, Morback, Jih
|
||||
German: Severin Heiniger, Tim Hartmann, DonPizza, Alex
|
||||
Norwegian: Protx, mjelva, TomP, John
|
||||
Romanian: nicusor
|
||||
Serbian: Ozzii, Krišan Darko
|
||||
Swedish: Malmis, Kim Joahnsson, Patrik-liind, Chris M
|
||||
Spanish: Syquus, Adolfo Jayme
|
||||
Portuguese (Brazil): lrrosa, diegosps
|
||||
Russian: Pavel Maryanov
|
||||
Polish: Tomasz 'Zen' Napierala
|
||||
Chinese: XsLiDian
|
||||
Finnish: Matti Ylönen
|
||||
The contributors and moderators of the translations are credited in the
|
||||
header of each translation file in the po/ directory.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
@@ -44,7 +32,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
See accompanying files GPL2.txt and GPL3.txt.
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
SABnzbd
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
0) LICENSE
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
(c) Copyright 2007-2026 by The SABnzbd-Team (sabnzbd.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
1) INSTALL with the Windows installer
|
||||
-------------------------------------------------------------------------------
|
||||
Just run the downloaded EXE file and the installer will start.
|
||||
It's just a simple standard installer.
|
||||
After installation, find the SABnzbd program in the Start menu and start it.
|
||||
|
||||
Within a few seconds your web browser will start and show the user interface.
|
||||
Use the "Help" button in the web-interface to be directed to the Help Wiki.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
2) INSTALL pre-built Windows binaries
|
||||
-------------------------------------------------------------------------------
|
||||
Unzip pre-built version to any folder of your liking.
|
||||
Start the SABnzbd.exe program.
|
||||
Within a few seconds your web browser will start and show the user interface.
|
||||
Use the "Help" button in the web-interface to be directed to the Help Wiki.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
3) INSTALL pre-built macOS binaries
|
||||
-------------------------------------------------------------------------------
|
||||
Download the DMG file, mount and drag the SABnzbd icon to Applications.
|
||||
Just like you do with so many apps.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
4) INSTALL with only sources
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Specific guides to install from source are available for Windows and macOS:
|
||||
https://sabnzbd.org/wiki/installation/install-macos
|
||||
https://sabnzbd.org/wiki/installation/install-from-source-windows
|
||||
|
||||
Only Python 3.9 and above is supported.
|
||||
|
||||
On Linux systems you need to install:
|
||||
par2 unrar python3-setuptools python3-pip
|
||||
|
||||
On non-X86 platforms, for which PyPI does not provide all pre-compiled packages,
|
||||
you also need to install these development libraries (exact names might differ per platform):
|
||||
libffi-dev libssl-dev
|
||||
|
||||
Unpack the ZIP-file containing the SABnzbd sources to any folder of your liking.
|
||||
|
||||
Inside the SABnzbd source directory, install all required Python packages by running:
|
||||
python3 -m pip install -r requirements.txt
|
||||
|
||||
If you want non-English languages, you need to compile the translations.
|
||||
Start this from a shell terminal (or command prompt):
|
||||
python3 tools/make_mo.py
|
||||
|
||||
To start SABnzbd, run this from a shell terminal (or command prompt):
|
||||
python3 -OO SABnzbd.py
|
||||
|
||||
Within a few seconds your web browser will start and show the user interface.
|
||||
Use the "Help" button in the web-interface to be directed to the Help Wiki.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
5) TROUBLESHOOTING
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Your browser may start up with just an error page.
|
||||
|
||||
This means that SABnzbd cannot use the default port 8080 to run its web-server on.
|
||||
Try to use another port, you'll need to use the a command window:
|
||||
SABnzbd.exe -s localhost:7777
|
||||
or
|
||||
python3 SABnzbd.py -s localhost:7777
|
||||
|
||||
You may of course try other port numbers too.
|
||||
|
||||
For troubleshooting on Windows you can use the program SABnzbd-console.exe.
|
||||
This will show a black window where logging information will be shown. This
|
||||
may help you solve problems easier.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
6) MORE INFORMATION
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Visit our wiki:
|
||||
https://sabnzbd.org/wiki/
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
7) CREDITS
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Several parts of SABnzbd were built by other people, illustrating the
|
||||
wonderful world of Free Open Source Software.
|
||||
See the licenses folder of the main program and of the skin folders.
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
*******************************************
|
||||
*** Known issues ***
|
||||
*******************************************
|
||||
|
||||
- To prevent unexpectedly large NZBs from eating your download quota you can set
|
||||
the option 'size_limit' on the Config->Special page.
|
||||
Any NZB larger than this size will be set to paused and get a low priority.
|
||||
|
||||
- When par2 or unrar hang up, never just stop SABnzbd.
|
||||
Instead use your operating system's task manager to stop the par2 or unrar program.
|
||||
Forcing SABnzbd to quit may damage your queues.
|
||||
|
||||
- Some Usenet servers have intermittent login (or other) problems.
|
||||
For these the server blocking method is not very favourable.
|
||||
There is an INI-only option that will limit blocks to 1 minute.
|
||||
no_penalties = 1
|
||||
See: https://sabnzbd.org/wiki/configuration/3.4/special
|
||||
|
||||
- Some third-party utilities try to probe SABnzbd API in such a way that you will
|
||||
often see warnings about unauthenticated access.
|
||||
If you are sure these probes are harmless, you can suppress the warnings by
|
||||
setting the option "api_warnings" to 0.
|
||||
See: https://sabnzbd.org/wiki/configuration/3.4/special
|
||||
|
||||
- On macOS you may encounter downloaded files with foreign characters.
|
||||
The par2 repair may fail when the files were created on a Windows system.
|
||||
The problem is caused by the PAR2 utility and we cannot fix this now.
|
||||
This does not apply to files inside RAR files.
|
||||
|
||||
- The "Watched Folder" sometimes fails to delete the NZB files it has
|
||||
processed. This happens when other software still accesses these files.
|
||||
Some third-party utilities supporting SABnzbd are known to do this.
|
||||
We cannot solve this problem, because the Operating System (read Windows)
|
||||
prevents the removal.
|
||||
|
||||
- When SABnzbd cannot send notification emails, check your virus scanner,
|
||||
firewall or security suite. It may be blocking outgoing email.
|
||||
|
||||
- When you are using external drives or network shares on macOS or Linux
|
||||
make sure that the drives are mounted.
|
||||
The operating system will simply redirect your files to alternative locations.
|
||||
You may have trouble finding the files when mounting the drive later.
|
||||
On macOS, SABnzbd will not create new folders in /Volumes.
|
||||
The result will be a failed job that can be retried once the volume has been mounted.
|
||||
|
||||
- If you use a mounted drive as "temporary download folder", it must be present when SABnzbd
|
||||
starts up. If not, SABnzbd will use the default location.
|
||||
You can make SABnzbd wait for a mount of the "temporary download folder" by setting
|
||||
Config->Special->wait_for_dfolder to 1.
|
||||
SABnzbd will appear to hang until the drive is mounted.
|
||||
@@ -16,15 +16,15 @@ If you want to know more you can head over to our website: https://sabnzbd.org.
|
||||
|
||||
SABnzbd has a few dependencies you'll need before you can get running. If you've previously run SABnzbd from one of the various Linux packages, then you likely already have all the needed dependencies. If not, here's what you're looking for:
|
||||
|
||||
- `python` (Python 3.9 and above, often called `python3`)
|
||||
- Python modules listed in `requirements.txt`. Install with `python3 -m pip install -r requirements.txt -U`
|
||||
- `python` (Python 3.10 and above, often called `python3`)
|
||||
- Python modules listed in `requirements.txt`. Install with `python3 -m pip install -r requirements.txt`
|
||||
- `par2` (Multi-threaded par2 installation guide can be found [here](https://sabnzbd.org/wiki/installation/multicore-par2))
|
||||
- `unrar` (make sure you get the "official" non-free version of unrar)
|
||||
|
||||
Optional:
|
||||
- See `requirements.txt`
|
||||
|
||||
Your package manager should supply these. If not, we've got links in our [installation guide](https://github.com/sabnzbd/sabnzbd/blob/master/INSTALL.txt).
|
||||
Your package manager should supply these. If not, we've got links in our [installation guide](https://sabnzbd.org/wiki/installation/install-off-modules).
|
||||
|
||||
## Running SABnzbd from source
|
||||
|
||||
|
||||
+39
-54
@@ -1,68 +1,53 @@
|
||||
Release Notes - SABnzbd 5.0.0 Release Candidate 2
|
||||
Release Notes - SABnzbd 5.1.0 Release Candidate 2
|
||||
=========================================================
|
||||
|
||||
This is the second release candidate of version 5.0.
|
||||
Please note the breaking changes described below!
|
||||
This is the second release candidate of version 5.1.
|
||||
|
||||
## New features in 5.0.0
|
||||
## New features in 5.1.0
|
||||
|
||||
* Added support for NNTP Pipelining which eliminates idle waiting between
|
||||
requests, significantly improving speeds on high-latency connections.
|
||||
Read more here: https://sabnzbd.org/wiki/advanced/nntp-pipelining
|
||||
New servers will have `Articles per request` set to `2` by default.
|
||||
* Implemented Direct Write to optimize assembly of downloaded files.
|
||||
Read more here: https://sabnzbd.org/wiki/advanced/direct-write
|
||||
* Post-processing scripts will always be executed, even for failed jobs.
|
||||
Make sure to check the status of the job in your scripts!
|
||||
* Removed Special setting `empty_postproc` as it is no longer needed.
|
||||
* Complete redesign of article cache.
|
||||
* Improved disk speed measurement in Status window.
|
||||
* Reduce delays between jobs during post-processing.
|
||||
* Improve handling of disks getting full.
|
||||
* Diskspace check will now included Category-specific folders.
|
||||
* If a download only has `.nzb` files inside, the new downloads
|
||||
will include the name of the original download.
|
||||
* No longer show tracebacks in the browser, only in the logs.
|
||||
* Dropped support for Python 3.8.
|
||||
* Windows: Added Windows ARM (portable) release.
|
||||
* Windows and macOS: Added HTML version of the Release Notes.
|
||||
* Windows and macOS: Update Python to 3.14.3, Unrar to 7.20,
|
||||
par2cmdline-turbo to 1.4 and 7zip to 26.00.
|
||||
* Refreshed the interface.
|
||||
* When Retrying a job, only the actually missing articles are tried again.
|
||||
This only works for jobs downloaded in 5.1.0 (or newer).
|
||||
* RSS items are now stored in the database instead of on disk.
|
||||
* New RSS `Age` rule to filter jobs based on their age.
|
||||
* Downloaded RSS items are cleared from the RSS database after 3 days.
|
||||
* Added support for filename and path pattern matching to the `Cleanup List`.
|
||||
* `Unwanted extensions` will also be removed after unpacking.
|
||||
* Allow job setting changes directly from `Extra queue columns`.
|
||||
* Added support for unpacking `.tar` files during post-processing.
|
||||
* Improved anonymization of the logs when using `Show Logging`.
|
||||
* Added `SAB_FILES` environment variable to Post-processing scripts,
|
||||
listing all files that resulted from the job.
|
||||
* New Servers will default to 16 connections instead of 8.
|
||||
* Use media duration as part of `Ignore Samples` detection.
|
||||
* Added option to (auto) sort the queue by Remaining Percentage.
|
||||
* Improved support for screen readers.
|
||||
* Parsing of header-encrypted RARs will use significantly fewer resources.
|
||||
* Add Ayatana AppIndicator tray support on GNOME.
|
||||
* Removed redundant `INSTALL.txt` file.
|
||||
* Dropped support for Python 3.9.
|
||||
* Windows and macOS: Updated Python to 3.14.6, Unrar to 7.23 and 7zip to 26.02.
|
||||
|
||||
## Bug fixes in 5.0.0
|
||||
|
||||
* `Check before download` could get stuck or fail to reject.
|
||||
* Several stability changes for the core download process.
|
||||
* If only par2 files were missing, jobs could get incorrectly aborted.
|
||||
* No error was shown in case NZB upload failed.
|
||||
* Correct mobile layout if `Full Width` is enabled.
|
||||
* Handle passwords that exceed Unrar's password limit.
|
||||
* Aborted Direct Unpack could result in no files being unpacked.
|
||||
* Encrypted RAR detection could sometimes fail.
|
||||
* Unwanted Extension check was unreliable on passworded downloads.
|
||||
* No longer exclusively lock all directory operations.
|
||||
* Improved handling of non-NFC unicode filenames.
|
||||
* Sorting of files inside jobs was inconsistent.
|
||||
* Linux: No longer break test-data in release package.
|
||||
* Windows: Tray icon disappears after Explorer restart.
|
||||
* macOS: Slow to start on some network setups.
|
||||
|
||||
## Changes to default settings for new installations in 5.0.0
|
||||
|
||||
* Default `Minimum Free Space for Temporary Download Folder` set to `500M`.
|
||||
* Enabled `verify_xff_header` setting by default.
|
||||
## Bug fixes in 5.1.0
|
||||
|
||||
* Prevent incorrect warnings about non-writeable directories.
|
||||
* Files unrelated to job could get removed by the `Cleanup List` logic.
|
||||
* Prevent path traversal in orphaned job APIs.
|
||||
* `Disk Full` errors from unrar were not handled gracefully during unpacking.
|
||||
* Memory leak could occur during article decoding.
|
||||
* In containers (like Docker), the Article Cache could exceed the memory limit.
|
||||
* Diskspace checks would be too strict when unpacking to different disk.
|
||||
* Prevent deadlock when a second signal arrives during shutdown procedure.
|
||||
* Verification using SFV-checks could fail, even though files were correct.
|
||||
* Windows: Uninstall would not remove Settings or Windows Service.
|
||||
* Windows: Warn for OS-limit if more than 1024 connections are configured.
|
||||
* macOS: AppleDouble files could result in failures in `Moving` stage.
|
||||
* macOS: Restarting the application resulted in Terminal window.
|
||||
|
||||
## Upgrade notices
|
||||
|
||||
* You can directly upgrade from version 3.0.0 and newer.
|
||||
* Upgrading from older versions will require performing a `Queue repair`.
|
||||
* Downgrading from version 4.2.0 or newer to 3.7.2 or older will require
|
||||
performing a `Queue repair` due to changes in the internal data format.
|
||||
|
||||
## Known problems and solutions
|
||||
|
||||
* Read `ISSUES.txt` or https://sabnzbd.org/wiki/introduction/known-issues
|
||||
|
||||
## Code Signing Policy
|
||||
|
||||
|
||||
+164
-243
@@ -19,8 +19,8 @@ import sys
|
||||
|
||||
# Trick to show a better message on older Python
|
||||
# releases that don't support walrus operator
|
||||
if Python_39_is_required_to_run_SABnzbd := sys.hexversion < 0x03090000:
|
||||
print("Sorry, requires Python 3.9 or above")
|
||||
if Python_39_is_required_to_run_SABnzbd := sys.hexversion < 0x030A00F0:
|
||||
print("Sorry, requires Python 3.10 or above")
|
||||
print("You can read more at: https://sabnzbd.org/wiki/installation/install-off-modules")
|
||||
sys.exit(1)
|
||||
|
||||
@@ -35,11 +35,11 @@ import socket
|
||||
import subprocess
|
||||
import multiprocessing
|
||||
import ssl
|
||||
import shlex
|
||||
import time
|
||||
import re
|
||||
import gc
|
||||
import threading
|
||||
import http.cookies
|
||||
from typing import Any
|
||||
|
||||
try:
|
||||
@@ -47,9 +47,7 @@ try:
|
||||
import Cheetah
|
||||
import feedparser
|
||||
import configobj
|
||||
import cherrypy
|
||||
import cheroot.errors
|
||||
import portend
|
||||
import uvicorn
|
||||
import cryptography
|
||||
import charset_normalizer
|
||||
import guessit
|
||||
@@ -68,6 +66,7 @@ import sabnzbd.interface
|
||||
from sabnzbd.constants import (
|
||||
DEF_NETWORKING_TIMEOUT,
|
||||
DEF_LOG_ERRFILE,
|
||||
DEF_LOG_ACCESSFILE,
|
||||
DEF_MAIN_TMPL,
|
||||
DEF_STD_WEB_DIR,
|
||||
DEF_WORKDIR,
|
||||
@@ -80,13 +79,17 @@ from sabnzbd.constants import (
|
||||
RSS_FILE_NAME,
|
||||
DEF_LOG_FILE,
|
||||
DEF_STD_CONFIG,
|
||||
DEF_LOG_CHERRY,
|
||||
CONFIG_BACKUP_HTTPS,
|
||||
)
|
||||
import sabnzbd.newsunpack
|
||||
from sabnzbd.misc import (
|
||||
exit_sab,
|
||||
split_host,
|
||||
port_is_free,
|
||||
find_free_port,
|
||||
bind_web_socket,
|
||||
HostNotAvailableError,
|
||||
xff_trusted_networks,
|
||||
create_https_certificates,
|
||||
ip_extract,
|
||||
set_serv_parms,
|
||||
@@ -98,7 +101,7 @@ from sabnzbd.misc import (
|
||||
set_https_verification,
|
||||
)
|
||||
from sabnzbd.filesystem import get_ext, real_path, long_path, globber_full, remove_file
|
||||
from sabnzbd.panic import panic_tmpl, panic_port, panic_host, panic, launch_a_browser
|
||||
from sabnzbd.panic import panic_tmpl, panic_port, panic_port_permission, panic_host, panic, launch_a_browser
|
||||
import sabnzbd.config as config
|
||||
import sabnzbd.cfg
|
||||
import sabnzbd.notifier as notifier
|
||||
@@ -115,7 +118,7 @@ try:
|
||||
from win32com.shell import shell, shellcon
|
||||
|
||||
from sabnzbd.utils.apireg import get_connection_info, set_connection_info
|
||||
import sabnzbd.sabtray
|
||||
import sabnzbd.sabtraywin
|
||||
|
||||
win32api.SetConsoleCtrlHandler(sabnzbd.sig_handler, True)
|
||||
except ImportError:
|
||||
@@ -194,7 +197,7 @@ class GUIHandler(logging.Handler):
|
||||
|
||||
def print_help():
|
||||
print()
|
||||
print(("Usage: %s [-f <configfile>] <other options>" % sabnzbd.MY_NAME))
|
||||
print("Usage: %s [-f <configfile>] <other options>" % sabnzbd.MY_NAME)
|
||||
print()
|
||||
print("Options marked [*] are stored in the config file")
|
||||
print()
|
||||
@@ -204,7 +207,7 @@ def print_help():
|
||||
print(" -t --templates <templ> Template directory [*]")
|
||||
print()
|
||||
print(" -l --logging <-1..2> Set logging level (-1=off, 0=least,2= most) [*]")
|
||||
print(" -w --weblogging Enable cherrypy access logging")
|
||||
print(" -w --weblogging Enable uvicorn access logging")
|
||||
print()
|
||||
print(" -b --browser <0..1> Auto browser launch (0= off, 1= on) [*]")
|
||||
if sabnzbd.WINDOWS:
|
||||
@@ -236,7 +239,7 @@ def print_help():
|
||||
|
||||
|
||||
def print_version():
|
||||
print(("""
|
||||
print("""
|
||||
%s-%s
|
||||
|
||||
(C) Copyright 2007-2026 by The SABnzbd-Team (sabnzbd.org)
|
||||
@@ -245,7 +248,7 @@ This is free software, and you are welcome to redistribute it
|
||||
under certain conditions. It is licensed under the
|
||||
GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version.
|
||||
|
||||
""" % (sabnzbd.MY_NAME, sabnzbd.__version__)))
|
||||
""" % (sabnzbd.MY_NAME, sabnzbd.__version__))
|
||||
|
||||
|
||||
def daemonize():
|
||||
@@ -290,18 +293,41 @@ def daemonize():
|
||||
os.dup2(f.fileno(), sys.stderr.fileno())
|
||||
|
||||
|
||||
def abort_and_show_error(browserhost, web_port, err=""):
|
||||
"""Abort program because of CherryPy troubles"""
|
||||
def abort_and_show_error(browserhost, web_port, err="", panic_func=panic_port):
|
||||
"""Abort program because the web-interface could not be started"""
|
||||
logging.error(T("Failed to start web-interface") + " : " + str(err))
|
||||
if not sabnzbd.DAEMON:
|
||||
if "49" in err:
|
||||
panic_host(browserhost, web_port)
|
||||
else:
|
||||
panic_port(browserhost, web_port)
|
||||
panic_func(browserhost, web_port)
|
||||
sabnzbd.halt()
|
||||
exit_sab(2)
|
||||
|
||||
|
||||
def abort_for_unusable_address(browserhost, port, err):
|
||||
"""Abort with the panic that matches why the address could not be used"""
|
||||
if isinstance(err, PermissionError):
|
||||
abort_and_show_error(browserhost, port, err, panic_func=panic_port_permission)
|
||||
else:
|
||||
abort_and_show_error(browserhost, port, err, panic_func=panic_host)
|
||||
|
||||
|
||||
def port_is_free_or_abort(host, port, browserhost):
|
||||
"""port_is_free(), but abort when the address cannot be used at all. Saying so
|
||||
up front beats a search that can only fail, followed by a message claiming
|
||||
some other program holds the port."""
|
||||
try:
|
||||
return port_is_free(host, port)
|
||||
except (PermissionError, HostNotAvailableError) as err:
|
||||
abort_for_unusable_address(browserhost, port, err)
|
||||
|
||||
|
||||
def find_free_port_or_abort(host, currentport, browserhost):
|
||||
"""find_free_port(), but abort when the address cannot be used at all"""
|
||||
try:
|
||||
return find_free_port(host, currentport)
|
||||
except (PermissionError, HostNotAvailableError) as err:
|
||||
abort_for_unusable_address(browserhost, currentport, err)
|
||||
|
||||
|
||||
def identify_web_template(key, defweb, wdir):
|
||||
"""Determine a correct web template set, return full template path"""
|
||||
if wdir is None:
|
||||
@@ -521,9 +547,12 @@ def get_webhost(web_host, web_port, https_port):
|
||||
"""Determine the webhost address and port,
|
||||
return (host, port, browserhost)
|
||||
"""
|
||||
|
||||
# Fallback to automatic hostname selection when the requested
|
||||
# all-interfaces bind address uses an unavailable address family.
|
||||
if web_host == "0.0.0.0" and not check_resolve("127.0.0.1"):
|
||||
web_host = ""
|
||||
elif web_host == "::" and not check_resolve("::1"):
|
||||
elif web_host in ("::", "::1") and not check_resolve("::1"):
|
||||
web_host = ""
|
||||
|
||||
if web_host is None:
|
||||
@@ -531,6 +560,10 @@ def get_webhost(web_host, web_port, https_port):
|
||||
else:
|
||||
sabnzbd.cfg.web_host.set(web_host)
|
||||
|
||||
# When passed as command-line arguments "[::]:8080" would result in
|
||||
# hostname set to "[::]" which cannot use used for getaddrinfo
|
||||
web_host_lookup = web_host.strip("[]")
|
||||
|
||||
# Get IP address, but discard APIPA/IPV6
|
||||
# If only APIPA's or IPV6 are found, fall back to localhost
|
||||
ipv4 = ipv6 = False
|
||||
@@ -538,9 +571,9 @@ def get_webhost(web_host, web_port, https_port):
|
||||
|
||||
try:
|
||||
# Valid user defined name?
|
||||
info = socket.getaddrinfo(web_host, None)
|
||||
info = socket.getaddrinfo(web_host_lookup, None)
|
||||
except socket.error:
|
||||
if not is_localhost(web_host):
|
||||
if not is_localhost(web_host_lookup):
|
||||
web_host = "0.0.0.0"
|
||||
try:
|
||||
info = socket.getaddrinfo(localhost, None)
|
||||
@@ -576,7 +609,7 @@ def get_webhost(web_host, web_port, https_port):
|
||||
|
||||
# :: will listen on all ipv6 interfaces (no ipv4 addresses)
|
||||
elif web_host in ("::", "[::]"):
|
||||
web_host = web_host.strip("[").strip("]")
|
||||
web_host = web_host_lookup
|
||||
# Assume '::1' == 'localhost'
|
||||
browserhost = localhost
|
||||
|
||||
@@ -601,12 +634,12 @@ def get_webhost(web_host, web_port, https_port):
|
||||
|
||||
# Some systems don't like brackets in numerical ipv6
|
||||
if sabnzbd.MACOS:
|
||||
web_host = web_host.strip("[]")
|
||||
web_host = web_host_lookup
|
||||
else:
|
||||
try:
|
||||
socket.getaddrinfo(web_host, None)
|
||||
except socket.error:
|
||||
web_host = web_host.strip("[]")
|
||||
web_host = web_host_lookup
|
||||
|
||||
if ipv6 and ipv4 and web_host == "" and sabnzbd.WINDOWS:
|
||||
helpful_warning(T("Please be aware the 0.0.0.0 hostname will need an IPv6 address for external access"))
|
||||
@@ -644,19 +677,6 @@ def get_webhost(web_host, web_port, https_port):
|
||||
return web_host, web_port, browserhost, https_port
|
||||
|
||||
|
||||
def attach_server(host, port, cert=None, key=None, chain=None):
|
||||
"""Define and attach server, optionally HTTPS"""
|
||||
if sabnzbd.cfg.ipv6_hosting() or "::1" not in host:
|
||||
http_server = cherrypy._cpserver.Server()
|
||||
http_server.bind_addr = (host, port)
|
||||
if cert and key:
|
||||
http_server.ssl_module = "builtin"
|
||||
http_server.ssl_certificate = cert
|
||||
http_server.ssl_private_key = key
|
||||
http_server.ssl_certificate_chain = chain
|
||||
http_server.subscribe()
|
||||
|
||||
|
||||
def is_sabnzbd_running(url):
|
||||
"""Return True when there's already a SABnzbd instance running."""
|
||||
try:
|
||||
@@ -670,19 +690,6 @@ def is_sabnzbd_running(url):
|
||||
return False
|
||||
|
||||
|
||||
def find_free_port(host, currentport):
|
||||
"""Return a free port, 0 when nothing is free"""
|
||||
n = 0
|
||||
while n < 10 and currentport <= 49151:
|
||||
try:
|
||||
portend.free(host, currentport, timeout=0.025)
|
||||
return currentport
|
||||
except Exception:
|
||||
currentport += 5
|
||||
n += 1
|
||||
return 0
|
||||
|
||||
|
||||
def check_for_sabnzbd(url, upload_nzbs, allow_browser=True):
|
||||
"""Check for a running instance of sabnzbd on this port
|
||||
allow_browser==True|None will launch the browser, False will not.
|
||||
@@ -829,7 +836,7 @@ def main():
|
||||
web_host = None
|
||||
web_port = None
|
||||
https_port = None
|
||||
cherrypylogging = None
|
||||
weblogging = None
|
||||
clean_up = False
|
||||
logging_level = None
|
||||
console_logging = False
|
||||
@@ -875,7 +882,7 @@ def main():
|
||||
elif opt in ("-c", "--clean"):
|
||||
clean_up = True
|
||||
elif opt in ("-w", "--weblogging"):
|
||||
cherrypylogging = True
|
||||
weblogging = True
|
||||
elif opt in ("-l", "--logging"):
|
||||
try:
|
||||
logging_level = int(arg)
|
||||
@@ -994,78 +1001,54 @@ def main():
|
||||
# When this is a daemon, just check and bail out if port in use
|
||||
if sabnzbd.DAEMON:
|
||||
if enable_https and https_port:
|
||||
try:
|
||||
portend.free(web_host, https_port, timeout=0.05)
|
||||
except IOError:
|
||||
if not port_is_free_or_abort(web_host, https_port, browserhost):
|
||||
abort_and_show_error(browserhost, web_port)
|
||||
except Exception:
|
||||
abort_and_show_error(browserhost, web_port, "49")
|
||||
try:
|
||||
portend.free(web_host, web_port, timeout=0.05)
|
||||
except IOError:
|
||||
if not port_is_free_or_abort(web_host, web_port, browserhost):
|
||||
abort_and_show_error(browserhost, web_port)
|
||||
except Exception:
|
||||
abort_and_show_error(browserhost, web_port, "49")
|
||||
|
||||
# Windows instance is reachable through registry
|
||||
url = None
|
||||
if sabnzbd.WINDOWS and not new_instance:
|
||||
url = get_connection_info()
|
||||
url = get_connection_info(inifile)
|
||||
if url and check_for_sabnzbd(url, upload_nzbs, autobrowser):
|
||||
exit_sab(0)
|
||||
|
||||
# SSL
|
||||
if enable_https:
|
||||
port = https_port or web_port
|
||||
try:
|
||||
portend.free(browserhost, port, timeout=0.05)
|
||||
except IOError as error:
|
||||
if str(error) == "Port not bound.":
|
||||
pass
|
||||
else:
|
||||
if not url:
|
||||
url = "https://%s:%s%s/api?" % (browserhost, port, sabnzbd.cfg.url_base())
|
||||
if new_instance or not check_for_sabnzbd(url, upload_nzbs, autobrowser):
|
||||
# Bail out if we have fixed our ports after first start-up
|
||||
if sabnzbd.cfg.fixed_ports():
|
||||
abort_and_show_error(browserhost, web_port)
|
||||
# Find free port to bind
|
||||
newport = find_free_port(browserhost, port)
|
||||
if newport > 0:
|
||||
# Save the new port
|
||||
if https_port:
|
||||
https_port = newport
|
||||
sabnzbd.cfg.https_port.set(newport)
|
||||
else:
|
||||
# In case HTTPS == HTTP port
|
||||
web_port = newport
|
||||
sabnzbd.cfg.web_port.set(newport)
|
||||
except Exception:
|
||||
# Something else wrong, probably badly specified host
|
||||
abort_and_show_error(browserhost, web_port, "49")
|
||||
if not port_is_free_or_abort(web_host, port, browserhost):
|
||||
if not url:
|
||||
url = "https://%s:%s%s/api?" % (browserhost, port, sabnzbd.cfg.url_base())
|
||||
if new_instance or not check_for_sabnzbd(url, upload_nzbs, autobrowser):
|
||||
# Bail out if we have fixed our ports after first start-up
|
||||
if sabnzbd.cfg.fixed_ports():
|
||||
abort_and_show_error(browserhost, web_port)
|
||||
# Find free port to bind
|
||||
newport = find_free_port_or_abort(web_host, port, browserhost)
|
||||
if newport:
|
||||
# Save the new port
|
||||
if https_port:
|
||||
https_port = newport
|
||||
sabnzbd.cfg.https_port.set(newport)
|
||||
else:
|
||||
# In case HTTPS == HTTP port
|
||||
web_port = newport
|
||||
sabnzbd.cfg.web_port.set(newport)
|
||||
|
||||
# NonSSL check if there's no HTTPS or we only use 1 port
|
||||
if not (enable_https and not https_port):
|
||||
try:
|
||||
portend.free(browserhost, web_port, timeout=0.05)
|
||||
except IOError as error:
|
||||
if str(error) == "Port not bound.":
|
||||
pass
|
||||
else:
|
||||
if not url:
|
||||
url = "http://%s:%s%s/api?" % (browserhost, web_port, sabnzbd.cfg.url_base())
|
||||
if new_instance or not check_for_sabnzbd(url, upload_nzbs, autobrowser):
|
||||
# Bail out if we have fixed our ports after first start-up
|
||||
if sabnzbd.cfg.fixed_ports():
|
||||
abort_and_show_error(browserhost, web_port)
|
||||
# Find free port to bind
|
||||
port = find_free_port(browserhost, web_port)
|
||||
if port > 0:
|
||||
sabnzbd.cfg.web_port.set(port)
|
||||
web_port = port
|
||||
except Exception:
|
||||
# Something else wrong, probably badly specified host
|
||||
abort_and_show_error(browserhost, web_port, "49")
|
||||
if not port_is_free_or_abort(web_host, web_port, browserhost):
|
||||
if not url:
|
||||
url = "http://%s:%s%s/api?" % (browserhost, web_port, sabnzbd.cfg.url_base())
|
||||
if new_instance or not check_for_sabnzbd(url, upload_nzbs, autobrowser):
|
||||
# Bail out if we have fixed our ports after first start-up
|
||||
if sabnzbd.cfg.fixed_ports():
|
||||
abort_and_show_error(browserhost, web_port)
|
||||
# Find free port to bind
|
||||
port = find_free_port_or_abort(web_host, web_port, browserhost)
|
||||
if port:
|
||||
sabnzbd.cfg.web_port.set(port)
|
||||
web_port = port
|
||||
|
||||
# We found a port, now we never check again
|
||||
sabnzbd.cfg.fixed_ports.set(True)
|
||||
@@ -1103,6 +1086,9 @@ def main():
|
||||
rollover_log = logging.handlers.RotatingFileHandler(
|
||||
sabnzbd.LOGFILE, "a+", sabnzbd.cfg.log_size(), sabnzbd.cfg.log_backups()
|
||||
)
|
||||
# Set the level here as well as on the logger, so records that were
|
||||
# created at a higher level and lowered afterwards are also dropped
|
||||
rollover_log.setLevel(LOGLEVELS[logging_level + 1])
|
||||
rollover_log.setFormatter(logging.Formatter(logformat))
|
||||
logger.addHandler(rollover_log)
|
||||
|
||||
@@ -1163,8 +1149,8 @@ def main():
|
||||
# Handle the several tray icons
|
||||
if sabnzbd.cfg.tray_icon() and not sabnzbd.DAEMON and not sabnzbd.WIN_SERVICE:
|
||||
if sabnzbd.WINDOWS:
|
||||
sabnzbd.WINTRAY = sabnzbd.sabtray.SABTrayThread()
|
||||
elif sabnzbd.LINUX_POWER and os.environ.get("DISPLAY"):
|
||||
sabnzbd.WINTRAY = sabnzbd.sabtraywin.SABTrayThread()
|
||||
elif sabnzbd.LINUX_POWER and (os.environ.get("DISPLAY") or os.environ.get("XDG_CURRENT_DESKTOP")):
|
||||
try:
|
||||
import gi
|
||||
|
||||
@@ -1211,41 +1197,14 @@ def main():
|
||||
# Starting of the webserver
|
||||
# Determine if this system has multiple definitions for 'localhost'
|
||||
hosts = all_localhosts()
|
||||
multilocal = len(hosts) > 1 and web_host in ("localhost", "0.0.0.0")
|
||||
|
||||
# For 0.0.0.0 CherryPy will always pick IPv4, so make sure the secondary localhost is IPv6
|
||||
if multilocal and web_host == "0.0.0.0" and hosts[1] == "127.0.0.1":
|
||||
hosts[1] = "::1"
|
||||
|
||||
# The Windows binary requires numeric localhost as primary address
|
||||
if web_host == "localhost":
|
||||
web_host = hosts[0]
|
||||
|
||||
if enable_https:
|
||||
if https_port:
|
||||
# Extra HTTP port for primary localhost
|
||||
attach_server(web_host, web_port)
|
||||
if multilocal:
|
||||
# Extra HTTP port for secondary localhost
|
||||
attach_server(hosts[1], web_port)
|
||||
# Extra HTTPS port for secondary localhost
|
||||
attach_server(hosts[1], https_port, https_cert, https_key, https_chain)
|
||||
web_port = https_port
|
||||
elif multilocal:
|
||||
# Extra HTTPS port for secondary localhost
|
||||
attach_server(hosts[1], web_port, https_cert, https_key, https_chain)
|
||||
|
||||
cherrypy.config.update(
|
||||
{
|
||||
"server.ssl_module": "builtin",
|
||||
"server.ssl_certificate": https_cert,
|
||||
"server.ssl_private_key": https_key,
|
||||
"server.ssl_certificate_chain": https_chain,
|
||||
}
|
||||
)
|
||||
elif multilocal:
|
||||
# Extra HTTP port for secondary localhost
|
||||
attach_server(hosts[1], web_port)
|
||||
if enable_https and https_port:
|
||||
# Separate HTTPS port: switch the main server to the HTTPS port
|
||||
web_port = https_port
|
||||
|
||||
if no_login:
|
||||
sabnzbd.cfg.username.set("")
|
||||
@@ -1255,108 +1214,55 @@ def main():
|
||||
if inet_exposure:
|
||||
sabnzbd.cfg.inet_exposure.set(inet_exposure)
|
||||
|
||||
mime_gzip = (
|
||||
"text/*",
|
||||
"application/javascript",
|
||||
"application/x-javascript",
|
||||
"application/json",
|
||||
"application/xml",
|
||||
"application/vnd.ms-fontobject",
|
||||
"application/font*",
|
||||
"image/svg+xml",
|
||||
)
|
||||
cherrypy.config.update(
|
||||
{
|
||||
"server.environment": "production",
|
||||
"server.socket_host": web_host,
|
||||
"server.socket_port": web_port,
|
||||
"server.shutdown_timeout": 0,
|
||||
"engine.autoreload.on": False,
|
||||
"tools.encode.on": True,
|
||||
"tools.gzip.on": True,
|
||||
"tools.gzip.mime_types": mime_gzip,
|
||||
"error_page.401": sabnzbd.panic.error_page_401,
|
||||
"error_page.404": sabnzbd.panic.error_page_404,
|
||||
}
|
||||
)
|
||||
|
||||
# Monkey-patch key validation to prevent cherrypy from stumbling over invalid cookies
|
||||
http.cookies._is_legal_key = lambda _: True
|
||||
|
||||
# Catch shutdown errors that can break cherrypy/cheroot
|
||||
# See https://github.com/cherrypy/cheroot/issues/710
|
||||
try:
|
||||
cheroot.errors.acceptable_sock_shutdown_exceptions += (OSError,)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# Do we want CherryPy Logging? Cannot be done via the config
|
||||
cherrypy.log.screen = False
|
||||
cherrypy.log.access_log.propagate = False
|
||||
if cherrypylogging:
|
||||
sabnzbd.WEBLOGFILE = os.path.join(logdir, DEF_LOG_CHERRY)
|
||||
cherrypy.log.access_file = str(sabnzbd.WEBLOGFILE)
|
||||
|
||||
# Force mimetypes (OS might overwrite them)
|
||||
forced_mime_types = {"css": "text/css", "js": "application/javascript"}
|
||||
|
||||
static = {
|
||||
"tools.staticdir.on": True,
|
||||
"tools.staticdir.dir": os.path.join(sabnzbd.WEB_DIR, "static"),
|
||||
"tools.staticdir.content_types": forced_mime_types,
|
||||
}
|
||||
staticcfg = {
|
||||
"tools.staticdir.on": True,
|
||||
"tools.staticdir.dir": os.path.join(sabnzbd.WEB_DIR_CONFIG, "staticcfg"),
|
||||
"tools.staticdir.content_types": forced_mime_types,
|
||||
}
|
||||
wizard_static = {
|
||||
"tools.staticdir.on": True,
|
||||
"tools.staticdir.dir": os.path.join(sabnzbd.WIZARD_DIR, "static"),
|
||||
"tools.staticdir.content_types": forced_mime_types,
|
||||
}
|
||||
|
||||
appconfig = {
|
||||
"/api": {
|
||||
"tools.auth_basic.on": False,
|
||||
"tools.response_headers.on": True,
|
||||
"tools.response_headers.headers": [("Access-Control-Allow-Origin", "*")],
|
||||
},
|
||||
"/static": static,
|
||||
"/wizard/static": wizard_static,
|
||||
"/favicon.ico": {
|
||||
"tools.staticfile.on": True,
|
||||
"tools.staticfile.filename": os.path.join(sabnzbd.WEB_DIR_CONFIG, "staticcfg", "ico", "favicon.ico"),
|
||||
},
|
||||
"/staticcfg": staticcfg,
|
||||
}
|
||||
|
||||
# Make available from both URLs
|
||||
main_page = sabnzbd.interface.MainPage()
|
||||
cherrypy.Application.relative_urls = "server"
|
||||
cherrypy.tree.mount(main_page, "/", config=appconfig)
|
||||
cherrypy.tree.mount(main_page, sabnzbd.cfg.url_base(), config=appconfig)
|
||||
|
||||
# Set authentication for CherryPy
|
||||
sabnzbd.interface.set_auth(cherrypy.config)
|
||||
logging.info("Starting web-interface on %s:%s", web_host, web_port)
|
||||
|
||||
sabnzbd.cfg.log_level.callback(guard_loglevel)
|
||||
|
||||
try:
|
||||
cherrypy.engine.start()
|
||||
except Exception:
|
||||
# Since the webserver is started by cherrypy in a separate thread, we can't really catch any
|
||||
# start-up errors. This try/except only catches very few errors, the rest is only shown in the console.
|
||||
logging.error(T("Failed to start web-interface: "), exc_info=True)
|
||||
abort_and_show_error(browserhost, web_port)
|
||||
|
||||
# Create a record of the active cert/key/chain files, for use with config.create_config_backup()
|
||||
if enable_https:
|
||||
for setting in CONFIG_BACKUP_HTTPS.values():
|
||||
if full_path := getattr(sabnzbd.cfg, setting).get_path():
|
||||
sabnzbd.CONFIG_BACKUP_HTTPS_OK.append(full_path)
|
||||
|
||||
# Do we want web-server access logging? Cannot be done via the config
|
||||
if weblogging:
|
||||
sabnzbd.WEBLOGFILE = os.path.join(logdir, DEF_LOG_ACCESSFILE)
|
||||
|
||||
# Catch logging using SABnzbd handlers
|
||||
uvicorn_logging_config = sabnzbd.interface.uvicorn_logging_config(sabnzbd.WEBLOGFILE)
|
||||
|
||||
# Claim the port here rather than letting uvicorn do it, because this is the
|
||||
# first point where the host and port are final. Everything before this was
|
||||
# only picking a port, and anything could still have taken it since.
|
||||
try:
|
||||
web_socket = bind_web_socket(web_host, web_port)
|
||||
except (PermissionError, HostNotAvailableError) as err:
|
||||
abort_for_unusable_address(browserhost, web_port, err)
|
||||
except OSError as err:
|
||||
logging.error(T("Failed to start web-interface: "), exc_info=True)
|
||||
abort_and_show_error(browserhost, web_port, err)
|
||||
|
||||
server_config = uvicorn.Config(
|
||||
sabnzbd.interface.create_app(),
|
||||
host=web_host,
|
||||
port=web_port,
|
||||
log_config=uvicorn_logging_config,
|
||||
ssl_keyfile=https_key if enable_https else None,
|
||||
ssl_certfile=https_cert if enable_https else None,
|
||||
ssl_ca_certs=https_chain if enable_https else None,
|
||||
proxy_headers=bool(sabnzbd.cfg.verify_xff_header()),
|
||||
forwarded_allow_ips=xff_trusted_networks(),
|
||||
)
|
||||
sabnzbd.WEB_SERVER = sabnzbd.interface.ThreadedServer(config=server_config, sockets=[web_socket])
|
||||
try:
|
||||
sabnzbd.WEB_SERVER.run_in_thread()
|
||||
except Exception:
|
||||
# The webserver runs in a separate thread; if it fails to start (bad cert,
|
||||
# unusable TLS material) surface the error and abort instead of hanging.
|
||||
# Details are also shown on the console.
|
||||
logging.error(T("Failed to start web-interface: "), exc_info=True)
|
||||
abort_and_show_error(browserhost, web_port)
|
||||
|
||||
# Set URL for browser
|
||||
if enable_https:
|
||||
sabnzbd.BROWSER_URL = "https://%s:%s%s" % (browserhost, web_port, sabnzbd.cfg.url_base())
|
||||
@@ -1365,7 +1271,7 @@ def main():
|
||||
|
||||
if sabnzbd.WINDOWS:
|
||||
# Write URL for uploads and version check directly to registry
|
||||
set_connection_info(f"{sabnzbd.BROWSER_URL}/api?apikey={sabnzbd.cfg.api_key()}")
|
||||
set_connection_info(f"{sabnzbd.BROWSER_URL}/api?apikey={sabnzbd.cfg.api_key()}", inifile)
|
||||
|
||||
if pid_path or pid_file:
|
||||
sabnzbd.pid_file(pid_path, pid_file, web_port)
|
||||
@@ -1413,6 +1319,8 @@ def main():
|
||||
logger.setLevel(level)
|
||||
if console_logging:
|
||||
console.setLevel(level)
|
||||
if not no_file_log:
|
||||
rollover_log.setLevel(level)
|
||||
|
||||
# 300 sec polling tasks
|
||||
if not timer % 100:
|
||||
@@ -1456,11 +1364,16 @@ def main():
|
||||
# Binaries require special restart
|
||||
if hasattr(sys, "frozen"):
|
||||
if sabnzbd.MACOS:
|
||||
# On macOS restart of app instead of embedded python
|
||||
my_args = " ".join(sys.argv[1:])
|
||||
cmd = 'kill -9 %s && open "%s" --args %s' % (os.getpid(), sys.executable, my_args)
|
||||
logging.info("Launching: %s", cmd)
|
||||
os.system(cmd)
|
||||
# Relaunch the .app via LaunchServices (clean env, proper menu-bar
|
||||
# context). Opening sys.executable directly makes macOS launch the
|
||||
# raw binary in Terminal.app — issue #3455.
|
||||
from Foundation import NSBundle
|
||||
|
||||
subprocess.Popen(
|
||||
'open -n "%s" --args %s'
|
||||
% (NSBundle.mainBundle().bundlePath(), " ".join(shlex.quote(arg) for arg in sys.argv[1:])),
|
||||
shell=True,
|
||||
)
|
||||
elif sabnzbd.WIN_SERVICE:
|
||||
# Use external service handler to do the restart
|
||||
# Wait 5 seconds to clean up
|
||||
@@ -1469,13 +1382,21 @@ def main():
|
||||
# Just a simple restart of the exe
|
||||
os.execv(sys.executable, ['"%s"' % arg for arg in sys.argv])
|
||||
else:
|
||||
# CherryPy has special logic to include interpreter options such as "-OO"
|
||||
cherrypy.engine._do_execv()
|
||||
# Re-exec with interpreter flags (replaces cherrypy.engine._do_execv)
|
||||
args = [sys.executable]
|
||||
if sys.flags.optimize == 1:
|
||||
args.append("-O")
|
||||
elif sys.flags.optimize >= 2:
|
||||
args.append("-OO")
|
||||
args.extend(sys.argv)
|
||||
os.execv(sys.executable, args)
|
||||
|
||||
# Send our final goodbyes!
|
||||
notifier.send_notification("SABnzbd", T("SABnzbd shutdown finished"), "startup")
|
||||
logging.info("Leaving SABnzbd")
|
||||
sabnzbd.pid_file()
|
||||
if sabnzbd.WEB_SERVER:
|
||||
sabnzbd.WEB_SERVER.stop()
|
||||
|
||||
try:
|
||||
sys.stderr.flush()
|
||||
@@ -1586,7 +1507,7 @@ def handle_windows_service():
|
||||
# In this case check for required parameters
|
||||
path = get_f_option(sab_opts)
|
||||
if not path:
|
||||
print(("The -f <path> parameter is required.\n" "Use: -f <path> %s" % service))
|
||||
print("The -f <path> parameter is required.\n" "Use: -f <path> %s" % service)
|
||||
return True
|
||||
|
||||
# First run the service installed, because this will
|
||||
|
||||
@@ -7,13 +7,13 @@ from PyInstaller.building.build_main import Analysis
|
||||
from PyInstaller.building.osx import BUNDLE
|
||||
from PyInstaller.utils.hooks import collect_data_files, collect_submodules
|
||||
|
||||
from builder.constants import EXTRA_FILES, EXTRA_FOLDERS, RELEASE_VERSION, RELEASE_VERSION_BASE, RELEASE_VERSION_TUPLE
|
||||
from builder.common import EXTRA_FILES, EXTRA_FOLDERS, RELEASE_VERSION, RELEASE_VERSION_BASE, RELEASE_VERSION_TUPLE
|
||||
|
||||
# Add extra files in the PyInstaller-spec
|
||||
extra_pyinstaller_files = []
|
||||
|
||||
# Add hidden imports
|
||||
extra_hiddenimports = ["Cheetah.DummyTransaction", "cheroot.ssl.builtin", "certifi"]
|
||||
extra_hiddenimports = ["Cheetah.DummyTransaction", "certifi"]
|
||||
extra_hiddenimports.extend(collect_submodules("apprise"))
|
||||
extra_hiddenimports.extend(collect_submodules("babelfish.converters"))
|
||||
extra_hiddenimports.extend(collect_submodules("guessit.data"))
|
||||
|
||||
@@ -32,14 +32,14 @@ with open(VERSION_FILE) as version_file:
|
||||
exec(version_file.read())
|
||||
RELEASE_VERSION = __version__
|
||||
|
||||
# Pre-releases are longer than 6 characters (e.g. 3.1.0Beta1 vs 3.1.0, but also 3.0.11)
|
||||
PRERELEASE = len(RELEASE_VERSION) > 5
|
||||
|
||||
# Parse the version info for Windows file properties information
|
||||
version_regexed = re.search(r"(\d+)\.(\d+)\.(\d+)([a-zA-Z]*)(\d*)", RELEASE_VERSION)
|
||||
RELEASE_VERSION_TUPLE = (int(version_regexed.group(1)), int(version_regexed.group(2)), int(version_regexed.group(3)), 0)
|
||||
RELEASE_VERSION_BASE = f"{RELEASE_VERSION_TUPLE[0]}.{RELEASE_VERSION_TUPLE[1]}.{RELEASE_VERSION_TUPLE[2]}"
|
||||
|
||||
# Pre-releases carry an alpha suffix (e.g. 5.1.0Beta1); stable releases don't (e.g. 5.1.0 or 5.1.10)
|
||||
PRERELEASE = bool(version_regexed.group(4))
|
||||
|
||||
# Define release name
|
||||
RELEASE_NAME = "SABnzbd-%s" % RELEASE_VERSION
|
||||
RELEASE_TITLE = "SABnzbd %s" % RELEASE_VERSION
|
||||
@@ -59,12 +59,10 @@ if platform.machine() == "ARM64":
|
||||
EXTRA_FILES = [
|
||||
RELEASE_README,
|
||||
"README.html",
|
||||
"INSTALL.txt",
|
||||
"LICENSE.txt",
|
||||
"GPL2.txt",
|
||||
"GPL3.txt",
|
||||
"COPYRIGHT.txt",
|
||||
"ISSUES.txt",
|
||||
]
|
||||
EXTRA_FOLDERS = [
|
||||
"scripts/",
|
||||
@@ -76,3 +74,15 @@ EXTRA_FOLDERS = [
|
||||
"interfaces/Config/",
|
||||
"icons/",
|
||||
]
|
||||
|
||||
|
||||
def pe_has_authenticode_signature(pe_file: str) -> bool:
|
||||
"""Check if a PE file (.exe) has an embedded Authenticode signature by
|
||||
inspecting the certificate table in the optional header data directory."""
|
||||
# Imported here as tools/extract_pot.py execs this file without
|
||||
# the build dependencies to get the RELEASE_VERSION_BASE
|
||||
import pefile
|
||||
|
||||
pe = pefile.PE(pe_file, fast_load=True)
|
||||
security = pe.OPTIONAL_HEADER.DATA_DIRECTORY[pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_SECURITY"]]
|
||||
return security.VirtualAddress != 0 and security.Size != 0
|
||||
+34
-7
@@ -16,6 +16,7 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import glob
|
||||
import importlib.util
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
@@ -29,8 +30,9 @@ import urllib.error
|
||||
import configobj
|
||||
import markdown
|
||||
import packaging.version
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from constants import (
|
||||
from common import (
|
||||
RELEASE_VERSION,
|
||||
RELEASE_VERSION_TUPLE,
|
||||
VERSION_FILE,
|
||||
@@ -44,6 +46,9 @@ from constants import (
|
||||
RELEASE_SRC,
|
||||
EXTRA_FILES,
|
||||
EXTRA_FOLDERS,
|
||||
APPDATA_FILE,
|
||||
RELEASE_VERSION_BASE,
|
||||
pe_has_authenticode_signature,
|
||||
)
|
||||
|
||||
|
||||
@@ -85,7 +90,7 @@ def run_external_command(command: list[str], print_output: bool = True, **kwargs
|
||||
|
||||
def run_git_command(parms):
|
||||
"""Run git command, raise error if it failed"""
|
||||
return run_external_command(["git"] + parms)
|
||||
return run_external_command(["git", *parms])
|
||||
|
||||
|
||||
def patch_version_file(release_name):
|
||||
@@ -110,6 +115,21 @@ def patch_version_file(release_name):
|
||||
ver.write(version_file)
|
||||
|
||||
|
||||
def verify_appdata():
|
||||
"""Verify that appdata file is updated"""
|
||||
if not isinstance(
|
||||
ET.parse(APPDATA_FILE).find(f"./releases/release[@version='{RELEASE_VERSION_BASE}']"),
|
||||
ET.Element,
|
||||
):
|
||||
release_missing = f"Could not find {RELEASE_VERSION_BASE} in {APPDATA_FILE}"
|
||||
if RELEASE_THIS:
|
||||
raise RuntimeError(release_missing)
|
||||
elif ON_GITHUB_ACTIONS:
|
||||
print(f"::warning file={APPDATA_FILE},title=Missing release::{release_missing}")
|
||||
else:
|
||||
print(release_missing)
|
||||
|
||||
|
||||
def build_readme_html(output_path: str):
|
||||
"""Convert the release notes Markdown to a styled HTML file."""
|
||||
with open(RELEASE_README, "r", encoding="utf-8") as f:
|
||||
@@ -175,7 +195,7 @@ def test_macos_min_version(binary_path: str):
|
||||
print(lines)
|
||||
raise RuntimeError(f"Could not determine minimum macOS version for {binary_path}")
|
||||
else:
|
||||
print(f"Skipping macOS version check, MACOSX_DEPLOYMENT_TARGET not set")
|
||||
print("Skipping macOS version check, MACOSX_DEPLOYMENT_TARGET not set")
|
||||
|
||||
|
||||
def test_sab_binary(binary_path: str):
|
||||
@@ -226,7 +246,7 @@ def test_sab_binary(binary_path: str):
|
||||
|
||||
# Parse API-key so we can do a graceful shutdown
|
||||
sab_config = configobj.ConfigObj(os.path.join(config_dir, "sabnzbd.ini"))
|
||||
urllib.request.urlopen(base_url + "shutdown/?apikey=" + sab_config["misc"]["api_key"], timeout=10)
|
||||
urllib.request.urlopen(base_url + "api?mode=shutdown&apikey=" + sab_config["misc"]["api_key"], timeout=10)
|
||||
sabnzbd_process.wait()
|
||||
|
||||
# Print logs for verification
|
||||
@@ -250,11 +270,12 @@ if __name__ == "__main__":
|
||||
raise FileNotFoundError("Run from the main SABnzbd source folder: python builder/package.py")
|
||||
|
||||
# Check if we have the needed certificates
|
||||
try:
|
||||
import certifi
|
||||
except ImportError:
|
||||
if importlib.util.find_spec("certifi") is None:
|
||||
raise FileNotFoundError("Need certifi module")
|
||||
|
||||
# Check if we have correct appdata file
|
||||
verify_appdata()
|
||||
|
||||
# Patch release file
|
||||
patch_version_file(RELEASE_VERSION)
|
||||
|
||||
@@ -316,6 +337,12 @@ if __name__ == "__main__":
|
||||
# Make sure it exists
|
||||
if not os.path.exists("dist/SABnzbd/SABnzbd.exe"):
|
||||
raise FileNotFoundError("SABnzbd executable not found, signed zip extraction failed")
|
||||
|
||||
# Make sure the executables are actually signed
|
||||
for exe_to_check in ("dist/SABnzbd/SABnzbd.exe", "dist/SABnzbd/SABnzbd-console.exe"):
|
||||
if not pe_has_authenticode_signature(exe_to_check):
|
||||
raise RuntimeError("%s is not signed!" % exe_to_check)
|
||||
print("%s has an Authenticode signature" % exe_to_check)
|
||||
elif RELEASE_THIS:
|
||||
raise FileNotFoundError("Signed SABnzbd executable not found, required for release!")
|
||||
else:
|
||||
|
||||
@@ -1,2 +1,27 @@
|
||||
PyGithub==2.9.0
|
||||
praw==7.8.1
|
||||
# All sub-dependencies are listed below and installed with --no-dependencies for security
|
||||
PyGithub==2.10.0
|
||||
praw==8.0.3
|
||||
pefile==2024.8.26
|
||||
|
||||
# PyGithub dependencies
|
||||
pynacl==1.6.2
|
||||
requests==2.34.2
|
||||
pyjwt==2.13.0
|
||||
typing-extensions==4.16.0
|
||||
urllib3==2.7.0
|
||||
|
||||
# praw dependencies
|
||||
prawcore==4.0.0
|
||||
defusedxml==0.7.1
|
||||
update-checker==1.0.0
|
||||
websocket-client==1.9.0
|
||||
|
||||
# requests dependencies
|
||||
charset_normalizer==3.5.1
|
||||
idna==3.19
|
||||
certifi==2026.7.22
|
||||
|
||||
# cryptography (via pyjwt[crypto]) dependencies
|
||||
cryptography==49.0.0
|
||||
cffi==2.1.1
|
||||
pycparser==3.0
|
||||
+78
-69
@@ -15,18 +15,16 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import github
|
||||
import praw
|
||||
import requests
|
||||
|
||||
from constants import (
|
||||
from common import (
|
||||
RELEASE_VERSION,
|
||||
RELEASE_VERSION_BASE,
|
||||
PRERELEASE,
|
||||
RELEASE_SRC,
|
||||
RELEASE_WIN_BIN_X64,
|
||||
@@ -36,8 +34,7 @@ from constants import (
|
||||
RELEASE_README,
|
||||
RELEASE_THIS,
|
||||
RELEASE_TITLE,
|
||||
APPDATA_FILE,
|
||||
ON_GITHUB_ACTIONS,
|
||||
pe_has_authenticode_signature,
|
||||
)
|
||||
|
||||
# Verify we have all assets
|
||||
@@ -51,28 +48,14 @@ files_to_check = (
|
||||
)
|
||||
for file_to_check in files_to_check:
|
||||
if not os.path.exists(file_to_check):
|
||||
raise RuntimeError("Not all release files are present!")
|
||||
raise RuntimeError("Release file %s is missing!" % file_to_check)
|
||||
print("All release files are present")
|
||||
|
||||
# Verify that appdata file is updated
|
||||
if not isinstance(ET.parse(APPDATA_FILE).find(f"./releases/release[@version='{RELEASE_VERSION_BASE}']"), ET.Element):
|
||||
release_missing = f"Could not find {RELEASE_VERSION_BASE} in {APPDATA_FILE}"
|
||||
if RELEASE_THIS:
|
||||
raise RuntimeError(release_missing)
|
||||
elif ON_GITHUB_ACTIONS:
|
||||
print(f"::warning file={APPDATA_FILE},title=Missing release::{release_missing}")
|
||||
else:
|
||||
print(release_missing)
|
||||
|
||||
# Calculate hashes for Synology release
|
||||
with open(RELEASE_SRC, "rb") as inp_file:
|
||||
source_data = inp_file.read()
|
||||
|
||||
print("---- Synology spksrc digest hashes ---- ")
|
||||
print(RELEASE_SRC, "SHA1", hashlib.sha1(source_data).hexdigest())
|
||||
print(RELEASE_SRC, "SHA256", hashlib.sha256(source_data).hexdigest())
|
||||
print(RELEASE_SRC, "MD5", hashlib.md5(source_data).hexdigest())
|
||||
print("----")
|
||||
# When releasing, the Windows installer must be signed
|
||||
if RELEASE_THIS:
|
||||
if not pe_has_authenticode_signature(RELEASE_WIN_INSTALLER):
|
||||
raise RuntimeError("%s is not signed!" % RELEASE_WIN_INSTALLER)
|
||||
print("%s has an Authenticode signature" % RELEASE_WIN_INSTALLER)
|
||||
|
||||
# Check if tagged as release and check for token
|
||||
gh_token = os.environ.get("AUTOMATION_GITHUB_TOKEN", "")
|
||||
@@ -80,18 +63,15 @@ if RELEASE_THIS and gh_token:
|
||||
gh_obj = github.Github(auth=github.Auth.Token(gh_token))
|
||||
gh_repo = gh_obj.get_repo("sabnzbd/sabnzbd")
|
||||
|
||||
# Read the release notes
|
||||
# Read the release notes (reused for the Reddit post below)
|
||||
with open(RELEASE_README, "r") as readme_file:
|
||||
readme_data = readme_file.read()
|
||||
|
||||
# We have to manually check if we already created this release
|
||||
for release in gh_repo.get_releases():
|
||||
if release.tag_name == RELEASE_VERSION:
|
||||
gh_release = release
|
||||
print("Found existing release %s" % gh_release.name)
|
||||
break
|
||||
else:
|
||||
# Did not find it, so create the release, use the GitHub tag we got as input
|
||||
# Find the existing release for this tag, or create a fresh draft
|
||||
try:
|
||||
gh_release = gh_repo.get_release(RELEASE_VERSION)
|
||||
print("Found existing release %s" % gh_release.name)
|
||||
except github.UnknownObjectException:
|
||||
print("Creating GitHub release SABnzbd %s" % RELEASE_VERSION)
|
||||
gh_release = gh_repo.create_git_release(
|
||||
tag=RELEASE_VERSION,
|
||||
@@ -101,38 +81,26 @@ if RELEASE_THIS and gh_token:
|
||||
prerelease=PRERELEASE,
|
||||
)
|
||||
|
||||
# Fetch existing assets, as overwriting is not allowed by GitHub
|
||||
gh_assets = gh_release.get_assets()
|
||||
# Overwriting an asset isn't allowed by GitHub, so delete any that already exist
|
||||
existing_assets = {asset.name: asset for asset in gh_release.get_assets()}
|
||||
for file_to_upload in files_to_check:
|
||||
if file_to_upload in existing_assets:
|
||||
print("Removing existing asset %s" % file_to_upload)
|
||||
existing_assets[file_to_upload].delete_asset()
|
||||
print("Uploading %s to release %s" % (file_to_upload, gh_release.name))
|
||||
gh_release.upload_asset(file_to_upload)
|
||||
|
||||
# Upload the assets
|
||||
for file_to_check in files_to_check:
|
||||
if os.path.exists(file_to_check):
|
||||
# Check if this file was previously uploaded
|
||||
if gh_assets.totalCount:
|
||||
for gh_asset in gh_assets:
|
||||
if gh_asset.name == file_to_check:
|
||||
print("Removing existing asset %s " % gh_asset.name)
|
||||
gh_asset.delete_asset()
|
||||
# Upload the new one
|
||||
print("Uploading %s to release %s" % (file_to_check, gh_release.name))
|
||||
gh_release.upload_asset(file_to_check)
|
||||
|
||||
# Check if we now have all files
|
||||
gh_new_assets = gh_release.get_assets()
|
||||
if gh_new_assets.totalCount:
|
||||
all_assets = [gh_asset.name for gh_asset in gh_new_assets]
|
||||
|
||||
# Check if we have all files, using set-comparison
|
||||
if set(files_to_check) == set(all_assets):
|
||||
print("All assets present, releasing %s" % RELEASE_VERSION)
|
||||
# Publish release
|
||||
gh_release.update_release(
|
||||
tag_name=RELEASE_VERSION,
|
||||
name=RELEASE_TITLE,
|
||||
message=readme_data,
|
||||
draft=False,
|
||||
prerelease=PRERELEASE,
|
||||
)
|
||||
# Publish the release once all assets are attached
|
||||
uploaded_assets = {asset.name for asset in gh_release.get_assets()}
|
||||
if set(files_to_check).issubset(uploaded_assets):
|
||||
print("All assets present, releasing %s" % RELEASE_VERSION)
|
||||
gh_release.update_release(
|
||||
tag_name=RELEASE_VERSION,
|
||||
name=RELEASE_TITLE,
|
||||
message=readme_data,
|
||||
draft=False,
|
||||
prerelease=PRERELEASE,
|
||||
)
|
||||
|
||||
# Update the website
|
||||
gh_repo_web = gh_obj.get_repo("sabnzbd/sabnzbd.github.io")
|
||||
@@ -219,6 +187,20 @@ if RELEASE_THIS and gh_token:
|
||||
print("Merging pull request in sabnzbd/sabnzbd.github.io for the update")
|
||||
update_pr.merge(merge_method="squash")
|
||||
|
||||
# Trigger the Docker image build at linuxserver.io
|
||||
# Branch "develop" builds the pre-releases, "master" the stable releases
|
||||
if linuxserver_token := os.environ.get("LINUXSERVER_WEBHOOK_TOKEN", ""):
|
||||
linuxserver_branch = "develop" if PRERELEASE else "master"
|
||||
print("Triggering linuxserver.io Docker build for branch %s" % linuxserver_branch)
|
||||
requests.post(
|
||||
"https://ci.linuxserver.io/generic-webhook-trigger/invoke?sabnzbd",
|
||||
headers={"Authorization": "Bearer %s" % linuxserver_token},
|
||||
json={"branch": linuxserver_branch},
|
||||
timeout=30,
|
||||
).raise_for_status()
|
||||
else:
|
||||
print("Missing LINUXSERVER_WEBHOOK_TOKEN")
|
||||
|
||||
# Only with GitHub success we proceed to Reddit
|
||||
if reddit_token := os.environ.get("REDDIT_TOKEN", ""):
|
||||
# Token format (without whitespace):
|
||||
@@ -235,9 +217,8 @@ if RELEASE_THIS and gh_token:
|
||||
subreddit_sabnzbd = reddit.subreddit("sabnzbd")
|
||||
subreddit_usenet = reddit.subreddit("usenet")
|
||||
|
||||
# Read the release notes
|
||||
with open(RELEASE_README, "r") as readme_file:
|
||||
readme_lines = readme_file.readlines()
|
||||
# Reuse the release notes read earlier, split into lines
|
||||
readme_lines = readme_data.splitlines(keepends=True)
|
||||
|
||||
# Put the download link after the title
|
||||
readme_lines[2] = "## https://sabnzbd.org/downloads\n\n"
|
||||
@@ -267,6 +248,34 @@ if RELEASE_THIS and gh_token:
|
||||
else:
|
||||
print("Missing REDDIT_TOKEN")
|
||||
|
||||
# Push release notes to Discord via an incoming webhook
|
||||
# Separate channels for testing (pre-release) and stable, both are required
|
||||
discord_webhook_testing = os.environ.get("DISCORD_WEBHOOK_TESTING", "")
|
||||
discord_webhook_stable = os.environ.get("DISCORD_WEBHOOK_STABLE", "")
|
||||
if discord_webhook_testing and discord_webhook_stable:
|
||||
discord_webhook = discord_webhook_testing if PRERELEASE else discord_webhook_stable
|
||||
print("Posting release notes to Discord")
|
||||
# Reuse the release notes read earlier: line 0 is the title header
|
||||
discord_lines = readme_data.splitlines(keepends=True)
|
||||
discord_title = discord_lines[0].lstrip("# ").strip()
|
||||
discord_body = "".join(discord_lines[2:])[:4096]
|
||||
requests.post(
|
||||
discord_webhook,
|
||||
json={
|
||||
"embeds": [
|
||||
{
|
||||
"title": discord_title,
|
||||
"url": gh_release.html_url,
|
||||
"description": discord_body,
|
||||
"color": 0xFFA500 if PRERELEASE else 0x00A550,
|
||||
}
|
||||
]
|
||||
},
|
||||
timeout=30,
|
||||
).raise_for_status()
|
||||
else:
|
||||
print("Missing DISCORD_WEBHOOK_TESTING and/or DISCORD_WEBHOOK_STABLE")
|
||||
|
||||
else:
|
||||
print("To push release to GitHub, first tag the commit.")
|
||||
print("Or missing the AUTOMATION_GITHUB_TOKEN, cannot push to GitHub without it.")
|
||||
+13
-10
@@ -1,20 +1,23 @@
|
||||
# Basic build requirements
|
||||
# Note that not all sub-dependencies are listed, but only ones we know could cause trouble
|
||||
pyinstaller==6.19.0
|
||||
packaging==26.0
|
||||
pyinstaller-hooks-contrib==2026.4
|
||||
# All sub-dependencies are listed below and installed with --no-dependencies for security
|
||||
pyinstaller==6.22.2
|
||||
packaging==26.3
|
||||
pyinstaller-hooks-contrib==2026.6
|
||||
altgraph==0.17.5
|
||||
wrapt==2.1.2
|
||||
setuptools==82.0.1
|
||||
markdown==3.10.2
|
||||
wrapt==2.3.0
|
||||
setuptools==84.0.0
|
||||
markdown==3.10.3
|
||||
pefile==2024.8.26
|
||||
|
||||
# For the Windows build
|
||||
pefile==2024.8.26; sys_platform == 'win32'
|
||||
pywin32-ctypes==0.2.3; sys_platform == 'win32'
|
||||
|
||||
# For the macOS build
|
||||
dmgbuild==1.6.7; sys_platform == 'darwin'
|
||||
mac-alias==2.2.3; sys_platform == 'darwin'
|
||||
macholib==1.16.4; sys_platform == 'darwin'
|
||||
ds-store==1.3.2; sys_platform == 'darwin'
|
||||
ds-store==1.3.3; sys_platform == 'darwin'
|
||||
PyNaCl==1.6.2; sys_platform == 'darwin'
|
||||
|
||||
# 48.0.0 is the last cryptography version shipping a macOS universal2 wheel (49+ is arm64-only)
|
||||
# See https://github.com/pyca/cryptography/issues/13520
|
||||
cryptography<49.0.0; sys_platform == 'darwin'
|
||||
@@ -18,6 +18,10 @@
|
||||
|
||||
Unicode true
|
||||
|
||||
; Must precede any data/header output. Solid LZMA dedups identical files (e.g. the
|
||||
; two SABnzbd*.pkg archives) and shrinks the whole installer.
|
||||
SetCompressor /SOLID lzma
|
||||
|
||||
!addplugindir builder\win\nsis\Plugins
|
||||
!addincludedir builder\win\nsis\Include
|
||||
|
||||
@@ -86,7 +90,6 @@ Unicode true
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Some default compiler settings (uncomment and change at will):
|
||||
SetCompress auto ; (can be off or force)
|
||||
SetDatablockOptimize on ; (can be off)
|
||||
CRCCheck on ; (can be off)
|
||||
AutoCloseWindow false ; (can be true for the window go away automatically at end)
|
||||
@@ -151,7 +154,6 @@ Unicode true
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!define MUI_UNPAGE_COMPONENTSPAGE_NODESC
|
||||
!insertmacro MUI_UNPAGE_COMPONENTS
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
@@ -165,6 +167,7 @@ Function PageFinishRun
|
||||
${If} $0 == true
|
||||
; Service is installed, start the service
|
||||
!insertmacro SERVICE "start" "SABnzbd" ""
|
||||
Pop $0
|
||||
${Else}
|
||||
; Service not installed, run executable as user
|
||||
${StdUtils.ExecShellAsUser} $0 "$INSTDIR\SABnzbd.exe" "" ""
|
||||
@@ -221,21 +224,32 @@ Section "SABnzbd" SecDummy
|
||||
; Shutdown any running service
|
||||
|
||||
!insertmacro SERVICE "stop" "SABnzbd" ""
|
||||
Pop $0
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Terminate SABnzbd.exe
|
||||
; Ask nicely first, but kill forcefully if it does not exit in time
|
||||
StrCpy $R1 0
|
||||
loop:
|
||||
${nsProcess::FindProcess} "SABnzbd.exe" $R0
|
||||
StrCmp $R0 0 0 endcheck
|
||||
IntCmp $R1 20 forcekill 0 forcekill
|
||||
${nsProcess::CloseProcess} "SABnzbd.exe" $R0
|
||||
IntOp $R1 $R1 + 1
|
||||
Sleep 500
|
||||
Goto loop
|
||||
forcekill:
|
||||
${nsProcess::KillProcess} "SABnzbd.exe" $R0
|
||||
Sleep 500
|
||||
endcheck:
|
||||
${nsProcess::Unload}
|
||||
|
||||
;------------------------------------------------------------------
|
||||
; Make sure old versions are gone (reg-key already read in onInt)
|
||||
StrCmp $PREV_INST_DIR "" noPrevInstallRemove
|
||||
; Only remove the directory if it actually contains a SABnzbd installation,
|
||||
; the registry value could point anywhere
|
||||
IfFileExists "$PREV_INST_DIR\SABnzbd.exe" 0 noPrevInstallRemove
|
||||
${RemovePrev} "$PREV_INST_DIR"
|
||||
Goto continueSetupAfterRemove
|
||||
|
||||
@@ -264,7 +278,9 @@ Section "SABnzbd" SecDummy
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "Comments" 'The automated Usenet download tool'
|
||||
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayIcon" '$INSTDIR\icons\sabnzbd.ico'
|
||||
|
||||
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "EstimatedSize" 40674
|
||||
; Calculate the actual installed size for Add/Remove Programs
|
||||
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
|
||||
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "EstimatedSize" "$0"
|
||||
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "NoRepair" -1
|
||||
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "NoModify" -1
|
||||
|
||||
@@ -351,7 +367,6 @@ Function .onInit
|
||||
endCheckDesktop:
|
||||
SetShellVarContext all
|
||||
|
||||
Push $1
|
||||
ReadRegStr $1 HKCR ".nzb" "" ; read current file association
|
||||
StrCmp "$1" "NZB File" noPrevInstall 0
|
||||
SectionSetFlags ${assoc} 0 ; Uncheck it when it wasn't checked before
|
||||
@@ -367,9 +382,34 @@ FunctionEnd
|
||||
; begin uninstall settings/section
|
||||
UninstallText $(MsgUninstall)
|
||||
|
||||
; Uninstaller variants of the servicelib functions, needed by the SERVICE macro.
|
||||
; APITAG is undefined again at the end of servicelib.nsh, so redefine it here.
|
||||
!define APITAG "W"
|
||||
|
||||
Function un.Service
|
||||
!insertmacro FUNC_SERVICE "un."
|
||||
FunctionEnd
|
||||
|
||||
Function un.GetParam
|
||||
!insertmacro FUNC_GETPARAM
|
||||
FunctionEnd
|
||||
|
||||
!undef APITAG
|
||||
|
||||
Section "un.$(MsgDelProgram)" Uninstall
|
||||
;make sure sabnzbd.exe isn't running..if so shut it down
|
||||
DetailPrint $(MsgShutting)
|
||||
|
||||
; Stop and remove the SABnzbd service, if it is installed
|
||||
!insertmacro SERVICE "installed" "SABnzbd" ""
|
||||
Pop $0
|
||||
${If} $0 == true
|
||||
!insertmacro SERVICE "stop" "SABnzbd" ""
|
||||
Pop $0
|
||||
!insertmacro SERVICE "delete" "SABnzbd" ""
|
||||
Pop $0
|
||||
${EndIf}
|
||||
|
||||
${nsProcess::KillProcess} "SABnzbd.exe" $R0
|
||||
${nsProcess::Unload}
|
||||
|
||||
@@ -380,7 +420,10 @@ Section "un.$(MsgDelProgram)" Uninstall
|
||||
DeleteRegKey HKEY_CURRENT_USER "Software\Classes\AppUserModelId\SABnzbd"
|
||||
DeleteRegKey HKEY_CURRENT_USER "Software\SABnzbd"
|
||||
|
||||
${RemovePrev} "$INSTDIR"
|
||||
; Only remove the directory if it actually contains a SABnzbd installation
|
||||
IfFileExists "$INSTDIR\SABnzbd.exe" 0 skipRemoveDir
|
||||
${RemovePrev} "$INSTDIR"
|
||||
skipRemoveDir:
|
||||
${RemovePrevShortcuts}
|
||||
|
||||
; Remove firewall entries
|
||||
@@ -393,8 +436,10 @@ Section "un.$(MsgDelProgram)" Uninstall
|
||||
SectionEnd ; end of uninstall section
|
||||
|
||||
Section /o "un.$(MsgDelSettings)" DelSettings
|
||||
DetailPrint "Uninstall settings $LOCALAPPDATA"
|
||||
Delete "$LOCALAPPDATA\sabnzbd\sabnzbd.ini"
|
||||
; The main uninstall section leaves the context on "all", which would make
|
||||
; $LOCALAPPDATA point to C:\ProgramData instead of the user's profile
|
||||
SetShellVarContext current
|
||||
DetailPrint "Uninstall settings $LOCALAPPDATA\sabnzbd"
|
||||
RMDir /r "$LOCALAPPDATA\sabnzbd"
|
||||
SectionEnd
|
||||
|
||||
@@ -503,16 +548,16 @@ SectionEnd
|
||||
LangString MsgNoWin7 ${LANG_SIMPCHINESE} "SABnzbd 仅支持 Windows 8.1 及更高版本。"
|
||||
|
||||
LangString MsgARM64Notice ${LANG_ENGLISH} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_CZECH} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_DANISH} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_GERMAN} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_SPANISH} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_CZECH} "Na naší stránce „Ke stažení“ je k dispozici verze SABnzbd pro architekturu ARM. Tento instalační program obsahuje pouze standardní verzi.$\nStiskněte tlačítko OK pro pokračování nebo Zrušit pro ukončení."
|
||||
LangString MsgARM64Notice ${LANG_DANISH} "En ARM-version af SABnzbd er tilgængelig på vores downloadside. Dette installationsprogram indeholder kun den almindelige version.$\nTryk på OK for at fortsætte eller Annuller for at afslutte."
|
||||
LangString MsgARM64Notice ${LANG_GERMAN} "Eine ARM-Version von SABnzbd ist auf unserer Downloads-Seite verfügbar. Dieses Installationsprogramm enthält nur die reguläre Version.$\nKlicken Sie auf OK, um fortzufahren, oder auf Abbrechen, um zu beenden."
|
||||
LangString MsgARM64Notice ${LANG_SPANISH} "Hay una versión ARM de SABnzbd disponible en nuestra página de descargas. Este instalador solo contiene la versión normal.$\nPulsa Aceptar para continuar o Cancelar para salir."
|
||||
LangString MsgARM64Notice ${LANG_FINNISH} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_FRENCH} "Une version ARM de SABnzbd est disponible sur notre page de téléchargement. Ce programme d'installation ne contient que la version standard.$\nCliquez sur OK pour continuer ou sur Annuler pour quitter."
|
||||
LangString MsgARM64Notice ${LANG_HEBREW} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_ITALIAN} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_HEBREW} "גרסת ARM של SABnzbd זמינה בעמוד ההורדות שלנו. תוכנת התקנה זו מכילה רק את הגרסה הרגילה.$\nלחץ על אישור כדי להמשיך או על ביטול כדי לצאת."
|
||||
LangString MsgARM64Notice ${LANG_ITALIAN} "Una versione ARM di SABnzbd è disponibile nella nostra pagina dei download. Questo programma di installazione contiene solo la versione normale.$\nPremi OK per continuare o Annulla per uscire."
|
||||
LangString MsgARM64Notice ${LANG_NORWEGIAN} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_DUTCH} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_DUTCH} "Er is een ARM versie van SABnzbd beschikbaar op onze Downloads pagina. Deze installatie bevat alleen de normale (niet-ARM) versie.$\nKlik OK om door te gaan of Annuleren om af te breken."
|
||||
LangString MsgARM64Notice ${LANG_POLISH} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_PORTUGUESEBR} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_ROMANIAN} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
@@ -520,7 +565,7 @@ SectionEnd
|
||||
LangString MsgARM64Notice ${LANG_SERBIAN} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_SWEDISH} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_TURKISH} "SABnzbd'nin ARM sürümü İndirmeler sayfamızda mevcuttur. Bu kurulum programı sadece normal sürümü içermektedir.$\nDevam etmek için Tamam'a veya çıkmak için İptal'e tıklayın."
|
||||
LangString MsgARM64Notice ${LANG_SIMPCHINESE} "An ARM version of SABnzbd is available on our Downloads page. This installer only contains the regular version.$\nPress OK to continue or Cancel to exit."
|
||||
LangString MsgARM64Notice ${LANG_SIMPCHINESE} "我们的下载页面提供 SABnzbd 的 ARM 版本。此安装程序仅包含常规版本。$\n按“确定”继续,或按“取消”退出。"
|
||||
|
||||
LangString MsgShutting ${LANG_ENGLISH} "Shutting down SABnzbd"
|
||||
LangString MsgShutting ${LANG_CZECH} "Vypínání SABnzbd"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
- Packaging/build
|
||||
- `builder/`: platform build scripts (DMG/EXE specs, `package.py`, `release.py`).
|
||||
- Platform folders `win/`, `macos/`, `linux/`, `snap/`: installer or platform-specific assets.
|
||||
- `admin/`, `builder/constants.py`, `licenses/`: release and licensing support files.
|
||||
- `admin/`, `builder/common.py`, `licenses/`: release and licensing support files.
|
||||
|
||||
- Documentation
|
||||
- Documentation website source is stored in the `sabnzbd.github.io` repo.
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<!-- Filebrowser modal -->
|
||||
<div class="modal fade" id="filebrowser_modal">
|
||||
<div class="modal fade" id="filebrowser_modal" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="filebrowser-modal-title">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title"></h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="filebrowser-modal-title"></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
</div>
|
||||
@@ -33,4 +33,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -1,10 +1,5 @@
|
||||
#if $pane == "Config"#
|
||||
#set global $root = '../'#
|
||||
#else#
|
||||
#set global $root = '../../'#
|
||||
#end if#
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="$active_lang" #if $rtl#dir="rtl"#end if#>
|
||||
<html lang="$active_lang" #if $rtl#dir="rtl"#end if# data-color-scheme="$color_scheme">
|
||||
<head>
|
||||
<title>
|
||||
SABnzbd $T('menu-config')
|
||||
@@ -14,7 +9,7 @@
|
||||
#if $pane == "Switches" then $T('cmenu-switches') else ""#
|
||||
#if $pane == "Servers" then $T('cmenu-servers') else ""#
|
||||
#if $pane == "Scheduling" then $T('cmenu-scheduling') else ""#
|
||||
#if $pane == "Email" then $T('cmenu-notif') else ""#
|
||||
#if $pane == "Notify" then $T('cmenu-notif') else ""#
|
||||
#if $pane == "Categories" then $T('cmenu-cat') else ""#
|
||||
#if $pane == "Sorting" then $T('cmenu-sorting') else ""#
|
||||
#if $pane == "Special" then $T('cmenu-special') else ""#
|
||||
@@ -25,20 +20,17 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, maximum-scale=1" />
|
||||
<meta name="apple-mobile-web-app-title" content="SABnzbd" />
|
||||
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="${root}staticcfg/ico/apple-touch-icon-76x76-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="${root}staticcfg/ico/apple-touch-icon-120x120-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="${root}staticcfg/ico/apple-touch-icon-152x152-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="${root}staticcfg/ico/apple-touch-icon-180x180-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="${root}staticcfg/ico/android-192x192.png" />
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="$url('staticcfg/ico/apple-touch-icon-76x76-precomposed.png', v=$cache_buster)" />
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="$url('staticcfg/ico/apple-touch-icon-120x120-precomposed.png', v=$cache_buster)" />
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="$url('staticcfg/ico/apple-touch-icon-152x152-precomposed.png', v=$cache_buster)" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="$url('staticcfg/ico/apple-touch-icon-180x180-precomposed.png', v=$cache_buster)" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="$url('staticcfg/ico/android-192x192.png', v=$cache_buster)" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="${root}staticcfg/bootstrap/css/bootstrap.min.css?v=$version" />
|
||||
<link rel="stylesheet" type="text/css" href="${root}staticcfg/css/chartist.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="${root}staticcfg/css/style.css?v=$version" />
|
||||
<!--#if $color_scheme not in ('Light', '') #-->
|
||||
<link rel="stylesheet" type="text/css" href="${root}staticcfg/css/${color_scheme}.css?v=$version"/>
|
||||
<!--#end if#-->
|
||||
<link rel="stylesheet" type="text/css" href="$url('staticcfg/bootstrap/css/bootstrap.min.css', v=$cache_buster)" />
|
||||
<link rel="stylesheet" type="text/css" href="$url('staticcfg/css/chartist.min.css', v=$cache_buster)" />
|
||||
<link rel="stylesheet" type="text/css" href="$url('staticcfg/css/style.css', v=$cache_buster)" />
|
||||
|
||||
<link rel="shortcut icon" href="${root}staticcfg/ico/favicon.ico?v=$version" />
|
||||
<link rel="shortcut icon" href="$url('staticcfg/ico/favicon.ico', v=$cache_buster)" />
|
||||
|
||||
<script type="text/javascript">
|
||||
// Keeping track of the form state
|
||||
@@ -46,10 +38,10 @@
|
||||
var formWasSubmitted = false;
|
||||
|
||||
// Information we need
|
||||
var sabSession = '$apikey';
|
||||
var rootURL = '${root}'
|
||||
var csrfToken = '$csrf_token';
|
||||
var rootURL = '$url()'
|
||||
var urlBase = '${url_base}'
|
||||
var folderBrowseUrl = '${root}api?mode=browse&output=json&apikey=$apikey';
|
||||
var folderBrowseUrl = "$url('api', mode='browse', output='json')";
|
||||
var folderSeperator = '#if $os.sep == '\\' then '\\\\' else '/'#'
|
||||
|
||||
// Translations
|
||||
@@ -65,9 +57,9 @@
|
||||
configTranslate.confirmLeave = "$T('confirmWithoutSavingPrompt')";
|
||||
configTranslate.searchPages = ['$T('cmenu-general')', '$T('cmenu-folders')', '$T('cmenu-switches')', '$T('cmenu-sorting')', '$T('cmenu-notif')', '$T('cmenu-special')']
|
||||
</script>
|
||||
<script type="text/javascript" src="${root}staticcfg/js/jquery-3.5.1.min.js?v=$version"></script>
|
||||
<script type="text/javascript" src="${root}staticcfg/bootstrap/js/bootstrap.min.js?v=$version"></script>
|
||||
<script type="text/javascript" src="${root}staticcfg/js/script.js?v=$version"></script>
|
||||
<script type="text/javascript" src="$url('staticcfg/js/jquery-3.7.1.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('staticcfg/bootstrap/js/bootstrap.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('staticcfg/js/script.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript">
|
||||
// Set default functions for the autocomplete everywhere
|
||||
|
||||
@@ -92,62 +84,62 @@
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
|
||||
<a class="navbar-logo navbar-logo-small" href="${root}" title="$T('Home')" data-placement="bottom">
|
||||
<a class="navbar-logo navbar-logo-small" href="$url()" title="$T('Home')" data-placement="bottom">
|
||||
#include $webdir + "/staticcfg/images/logo-small.svg"#
|
||||
</a>
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li>
|
||||
<a href="${root}config/general/" #if $pane == "General" then 'class="active"' else ""#>
|
||||
<a href="$url('config/general')" #if $pane == "General" then 'class="active"' else ""#>
|
||||
<span class="glyphicon glyphicon-cog"></span>
|
||||
<strong>$T('cmenu-general')</strong>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="${root}config/folders/" #if $pane == "Folders" then 'class="active"' else ""#>
|
||||
<a href="$url('config/folders')" #if $pane == "Folders" then 'class="active"' else ""#>
|
||||
<span class="glyphicon glyphicon-folder-open"></span>
|
||||
<strong>$T('cmenu-folders')</strong>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="${root}config/server/" #if $pane == "Servers" then 'class="active"' else ""#>
|
||||
<a href="$url('config/server')" #if $pane == "Servers" then 'class="active"' else ""#>
|
||||
<span class="glyphicon glyphicon-sort"></span>
|
||||
<strong>$T('cmenu-servers')</strong>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="${root}config/categories/" #if $pane == "Categories" then 'class="active"' else ""#>
|
||||
<a href="$url('config/categories')" #if $pane == "Categories" then 'class="active"' else ""#>
|
||||
<span class="glyphicon glyphicon-tag"></span>
|
||||
<strong>$T('cmenu-cat')</strong>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="${root}config/switches/" #if $pane == "Switches" then 'class="active"' else ""#>
|
||||
<a href="$url('config/switches')" #if $pane == "Switches" then 'class="active"' else ""#>
|
||||
<span class="glyphicon glyphicon-check"></span>
|
||||
<strong>$T('cmenu-switches')</strong>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="${root}config/sorting/" #if $pane == "Sorting" then 'class="active"' else ""#>
|
||||
<a href="$url('config/sorting')" #if $pane == "Sorting" then 'class="active"' else ""#>
|
||||
<span class="glyphicon glyphicon-sort-by-alphabet"></span>
|
||||
<strong>$T('cmenu-sorting')</strong>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="${root}config/notify/" #if $pane == "Email" then 'class="active"' else ""#>
|
||||
<a href="$url('config/notify')" #if $pane == "Notify" then 'class="active"' else ""#>
|
||||
<span class="glyphicon glyphicon-comment"></span>
|
||||
<strong>$T('cmenu-notif')</strong>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="${root}config/scheduling/" #if $pane == "Scheduling" then 'class="active"' else ""#>
|
||||
<a href="$url('config/scheduling')" #if $pane == "Scheduling" then 'class="active"' else ""#>
|
||||
<span class="glyphicon glyphicon-time"></span>
|
||||
<strong>$T('cmenu-scheduling')</strong>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="${root}config/rss/" #if $pane == "RSS" then 'class="active"' else ""#>
|
||||
<a href="$url('config/rss')" #if $pane == "RSS" then 'class="active"' else ""#>
|
||||
<svg class="rss-icon-svg" viewBox="0 0 8 8">
|
||||
<rect class="rss-button" width="8" height="8" />
|
||||
<circle class="rss-symbol" cx="2" cy="6" r="1" />
|
||||
@@ -158,7 +150,7 @@
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="${root}config/special/" #if $pane == "Special" then 'class="active"' else ""#>
|
||||
<a href="$url('config/special')" #if $pane == "Special" then 'class="active"' else ""#>
|
||||
<span class="glyphicon glyphicon-education"></span>
|
||||
<strong>$T('cmenu-special')</strong>
|
||||
</a>
|
||||
@@ -170,14 +162,14 @@
|
||||
</a>
|
||||
</li>
|
||||
<li class="dropdown" id="search-menu">
|
||||
<a data-toggle="dropdown" href="#">
|
||||
<a data-toggle="dropdown" href="#" aria-label="$T('cmenu-search')" aria-controls="search-dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-search"></span>
|
||||
<strong><span class="glyphicon glyphicon-search"></span></strong>
|
||||
</a>
|
||||
<ul class="dropdown-menu" id="search-dropdown">
|
||||
<li>
|
||||
<form onsubmit="return false">
|
||||
<input type="text" name="config-search" id="search-box" placeholder="$T('cmenu-search')" onkeyup="doConfigSearch(this)">
|
||||
<input type="text" name="config-search" id="search-box" placeholder="$T('cmenu-search')" aria-label="$T('cmenu-search')" aria-controls="search-dropdown" onkeyup="doConfigSearch(this)">
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
</div>
|
||||
|
||||
<div class="colmask">
|
||||
<div class="padding">
|
||||
<div class="section padding">
|
||||
<h5 class="copyright">Copyright © 2007-2026 by The SABnzbd-Team (<a href="https://sabnzbd.org/" target="_blank">sabnzbd.org</a>)</h5>
|
||||
<p class="copyright"><small>$T('yourRights')</small></p>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<h5 class="darkred"><strong>$T('explain-relFolder'):</strong> <span class="path">$defdir</span></h5>
|
||||
<!--#for $cur, $slot in enumerate($slotinfo)#-->
|
||||
<!--#set $cansort = $slot.name != '*' and $slot.name != ''#-->
|
||||
<form action="save" method="post" <!--#if $cansort#-->class="sorting-row"<!--#end if#-->>
|
||||
<form action="$url('config/categories/save')" method="post" class="fullform <!--#if $cansort then 'sorting-row' else ''#-->">
|
||||
<table class="catTable">
|
||||
<!--#if $cur == 0#-->
|
||||
<tr>
|
||||
@@ -28,7 +28,6 @@
|
||||
<span class="glyphicon glyphicon-option-vertical"></span>
|
||||
</td>
|
||||
<td>
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="order" value="$slot.order" />
|
||||
<input type="hidden" value="$slot.name" name="name" />
|
||||
<!--#if $slot.name != '*'#-->
|
||||
@@ -103,12 +102,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="${root}staticcfg/js/jquery-ui.min.js"></script>
|
||||
<script type="text/javascript" src="$url('staticcfg/js/jquery-ui.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function() {
|
||||
jQuery('.delCat').click(function() {
|
||||
var theForm = jQuery(this).closest("form");
|
||||
theForm.attr("action", "delete").submit();
|
||||
theForm.attr("action", "$url('config/categories/delete')").submit();
|
||||
});
|
||||
|
||||
// Add autocomplete and file-browser
|
||||
@@ -128,8 +127,8 @@
|
||||
var data = {}
|
||||
jQuery(elm).extractFormDataTo(data);
|
||||
jQuery.ajax({
|
||||
type: "GET",
|
||||
url: window.location.pathname + 'save',
|
||||
type: "POST",
|
||||
url: "$url('config/categories/save')",
|
||||
data: data,
|
||||
async: false // To prevent race-conditions when updating categories
|
||||
})
|
||||
|
||||
@@ -8,10 +8,8 @@
|
||||
<input type="checkbox" id="advanced-settings-button" name="advanced-settings-button"> $T('button-advanced')
|
||||
</label>
|
||||
</div>
|
||||
<form action="saveDirectories" method="post" name="fullform" class="fullform" autocomplete="off">
|
||||
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
|
||||
<form action="$url('config/folders/save')" method="post" class="fullform" autocomplete="off">
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<input type="hidden" id="ajax" name="ajax" value="1" />
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
<h3>$T('userFolders') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
@@ -35,7 +33,7 @@
|
||||
<div class="field-pair">
|
||||
<label class="config" for="complete_dir">$T('opt-complete_dir')</label>
|
||||
<input type="text" name="complete_dir" id="complete_dir" value="$complete_dir" data-initialdir="$my_home" />
|
||||
<a class="btn btn-default" href="${root}config/sorting/"><span class="glyphicon glyphicon-sort-by-alphabet"></span> $T('cmenu-sorting')</a>
|
||||
<a class="btn btn-default" href="$url('config/sorting')"><span class="glyphicon glyphicon-sort-by-alphabet"></span> $T('cmenu-sorting')</a>
|
||||
<span class="desc">$T('explain-complete_dir') <br/> $T('explain-complete_dir-sorting')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
@@ -113,7 +111,7 @@
|
||||
<div class="field-pair">
|
||||
<label class="config" for="log_dir">$T('opt-log_dir')</label>
|
||||
<input type="text" name="log_dir" id="log_dir" value="$log_dir" data-initialdir="$my_lcldata" />
|
||||
<a class="btn btn-default" id="purge_log_files" href="${root}"><span class="glyphicon glyphicon-trash"></span> $T('purge_log_files')</a>
|
||||
<a class="btn btn-default" id="purge_log_files" href="$url()"><span class="glyphicon glyphicon-trash"></span> $T('purge_log_files')</a>
|
||||
<span class="desc">$T('explain-log_dir')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
@@ -139,8 +137,8 @@
|
||||
if ( confirm("$T('confirm')") ) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../../api",
|
||||
data: {mode: 'config', name: 'purge_log_files', output: 'json', apikey: jQuery('#apikey').val()}
|
||||
url: "$url('api')",
|
||||
data: {mode: 'config', name: 'purge_log_files', output: 'json'}
|
||||
})
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
<input type="checkbox" id="advanced-settings-button" name="advanced-settings-button"> $T('button-advanced')
|
||||
</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" />
|
||||
<form action="$url('config/general/save')" method="post" class="fullform" autocomplete="off">
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
@@ -46,7 +44,6 @@
|
||||
<!--#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>
|
||||
@@ -223,9 +220,7 @@
|
||||
</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" />
|
||||
<form action="$url('config/general/upload_config')" method="post" class="fullform" autocomplete="off" enctype="multipart/form-data">
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<div class="section">
|
||||
<div class="col2">
|
||||
@@ -252,7 +247,7 @@
|
||||
</form>
|
||||
</div><!-- /colmask -->
|
||||
|
||||
<div class="modal fade" id="modal_qr">
|
||||
<div class="modal fade" id="modal_qr" tabindex="-1" role="dialog" aria-modal="true" aria-label="$T('explain-qr-code')">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
@@ -280,8 +275,6 @@ jQuery(document).ready(function(){
|
||||
// Skip the fancy stuff, just submit
|
||||
this.submit()
|
||||
})
|
||||
// No JSON response
|
||||
jQuery('#ajax').val('')
|
||||
})
|
||||
hideOrShowTranslate()
|
||||
|
||||
@@ -312,17 +305,16 @@ jQuery(document).ready(function(){
|
||||
safeCheck.on('change', checkSafety)
|
||||
|
||||
// Click functions
|
||||
jQuery('#apikey, #nzbkey').click(function () { jQuery(this).select() });
|
||||
jQuery('#apikey_display, #nzbkey').click(function () { jQuery(this).select() });
|
||||
|
||||
jQuery('#generate_new_apikey').click(function () {
|
||||
if (confirm("$T('confirm')")) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../../api",
|
||||
data: {mode:'config', name:'set_apikey', apikey: jQuery('#apikey').val()},
|
||||
url: "$url('api')",
|
||||
data: { mode: 'config', name: 'set_apikey' },
|
||||
success: function(msg){
|
||||
jQuery('#apikey').val(msg);
|
||||
document.location = document.location;
|
||||
jQuery('#apikey_display').val(msg.apikey);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -331,11 +323,10 @@ jQuery(document).ready(function(){
|
||||
if (confirm("$T('confirm')")) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../../api",
|
||||
data: { mode:'config', name:'set_nzbkey', apikey: jQuery('#apikey').val() },
|
||||
success: function(msg){
|
||||
jQuery('#nzbkey').val(msg);
|
||||
document.location = document.location;
|
||||
url: "$url('api')",
|
||||
data: { mode: 'config', name: 'set_nzbkey' },
|
||||
success: function(msg) {
|
||||
jQuery('#nzbkey').val(msg.nzbkey);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -366,8 +357,8 @@ jQuery(document).ready(function(){
|
||||
// Submit request and then restart
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../../api",
|
||||
data: { mode: 'config', name: 'regenerate_certs', apikey: jQuery('#apikey').val() },
|
||||
url: "$url('api')",
|
||||
data: { mode: 'config', name: 'regenerate_certs' },
|
||||
success: function(msg) {
|
||||
do_restart()
|
||||
}
|
||||
@@ -404,8 +395,8 @@ jQuery(document).ready(function(){
|
||||
jQuery('#create_backup').click(function () {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../../api",
|
||||
data: {mode:'config', name:'create_backup', output:'json', apikey: jQuery('#apikey').val()},
|
||||
url: "$url('api')",
|
||||
data: { mode: 'config', name: 'create_backup', output: 'json' },
|
||||
success: function(data) {
|
||||
if(data.value.result) {
|
||||
alert("$T('backup'):\n" + data.value.message)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!--#set global $pane="Email"#-->
|
||||
<!--#set global $pane="Notify"#-->
|
||||
<!--#set global $help_uri = $confighelpuri + "notifications"#-->
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
<!--#def show_notify_checkboxes($section_label)#-->
|
||||
<!--#for $type in $notify_types#-->
|
||||
<div class="field-pair">
|
||||
<label class="config wide" for="${section_label}_prio_$type">
|
||||
<input type="checkbox" class="notify-checkboxes" name="${section_label}_prio_$type" id="${section_label}_prio_$type" value="1" <!--#if $getVar($section_label + '_prio_' + $type) then 'checked="checked"' else ""#--> />
|
||||
<label class="config" for="${section_label}_prio_$type">
|
||||
$T($notify_types[$type]).replace('/', ' / ')
|
||||
</label>
|
||||
<input type="checkbox" name="${section_label}_prio_$type" id="${section_label}_prio_$type" value="1" <!--#if $getVar($section_label + '_prio_' + $type) then 'checked="checked"' else ""#--> />
|
||||
|
||||
</div>
|
||||
<!--#end for#-->
|
||||
<!--#end def#-->
|
||||
@@ -29,10 +30,8 @@
|
||||
<!--#end def#-->
|
||||
|
||||
<div class="colmask">
|
||||
<form action="saveNotify" method="post" name="fullform" class="fullform" autocomplete="off">
|
||||
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
|
||||
<form action="$url('config/notify/save')" method="post" class="fullform" autocomplete="off">
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<input type="hidden" id="ajax" name="ajax" value="1" />
|
||||
<div class="section" id="email">
|
||||
<div class="col2">
|
||||
<h3>$T('cmenu-email') <a href="$help_uri#toc0" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
@@ -93,10 +92,10 @@
|
||||
</div>
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default" type="button" id="test_email" rel="$T('askTestEmail')"><span class="glyphicon glyphicon-envelope"></span> $T('link-testEmail')</button>
|
||||
</div>
|
||||
<div class="field-pair result-box">
|
||||
<div class="alert"></div>
|
||||
<button class="btn btn-default" type="button" id="test_email" rel="$T('askTestEmail')" aria-busy="false"><span class="glyphicon glyphicon-envelope" aria-hidden="true"></span> $T('link-testEmail')</button>
|
||||
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div class="alert"></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -117,10 +116,10 @@
|
||||
$show_notify_checkboxes('ncenter')
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default" type="button" id="test_notif"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
|
||||
</div>
|
||||
<div class="field-pair result-box">
|
||||
<div class="alert"></div>
|
||||
<button class="btn btn-default" type="button" id="test_notif" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
|
||||
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div class="alert"></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -143,10 +142,10 @@
|
||||
$show_notify_checkboxes('acenter')
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default" type="button" id="test_windows"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
|
||||
</div>
|
||||
<div class="field-pair result-box">
|
||||
<div class="alert"></div>
|
||||
<button class="btn btn-default" type="button" id="test_windows" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
|
||||
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div class="alert"></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -169,10 +168,10 @@
|
||||
$show_notify_checkboxes('ntfosd')
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default" type="button" id="test_osd"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
|
||||
</div>
|
||||
<div class="field-pair result-box">
|
||||
<div class="alert"></div>
|
||||
<button class="btn btn-default" type="button" id="test_osd" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
|
||||
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div class="alert"></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -209,17 +208,17 @@
|
||||
<label class="config" for="${section_label}_target_${type}">
|
||||
$T($notify_types[$type]).replace('/', ' / ')
|
||||
</label>
|
||||
<input type="checkbox" name="${section_label}_target_${type}_enable" id="${section_label}_target_${type}_enable" value="1" <!--#if $getVar($section_label + '_target_' + $type + '_enable') then 'checked="checked"' else ""#--> />
|
||||
<input type="checkbox" class="notify-checkboxes" name="${section_label}_target_${type}_enable" id="${section_label}_target_${type}_enable" value="1" <!--#if $getVar($section_label + '_target_' + $type + '_enable') then 'checked="checked"' else ""#--> />
|
||||
<input type="text" name="${section_label}_target_${type}" id="${section_label}_target_${type}" value="$getVar($section_label + '_target_' + $type)" placeholder="$T('opt-apprise_urls')" />
|
||||
</div>
|
||||
<!--#end for#-->
|
||||
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default" type="button" id="test_apprise"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
|
||||
</div>
|
||||
<div class="field-pair result-box">
|
||||
<div class="alert"></div>
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default" type="button" id="test_apprise" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
|
||||
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div class="alert"></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -255,10 +254,10 @@
|
||||
$show_notify_checkboxes('nscript')
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default" type="button" id="test_nscript"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
|
||||
</div>
|
||||
<div class="field-pair result-box">
|
||||
<div class="alert"></div>
|
||||
<button class="btn btn-default" type="button" id="test_nscript" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
|
||||
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div class="alert"></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -300,10 +299,10 @@
|
||||
<!--#end for#-->
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default" type="button" id="test_prowl"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
|
||||
</div>
|
||||
<div class="field-pair result-box">
|
||||
<div class="alert"></div>
|
||||
<button class="btn btn-default" type="button" id="test_prowl" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
|
||||
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div class="alert"></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -366,10 +365,10 @@
|
||||
<!--#end for#-->
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default" type="button" id="test_pushover"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
|
||||
</div>
|
||||
<div class="field-pair result-box">
|
||||
<div class="alert"></div>
|
||||
<button class="btn btn-default" type="button" id="test_pushover" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
|
||||
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div class="alert"></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -402,11 +401,11 @@
|
||||
<!--#end if#-->
|
||||
$show_notify_checkboxes('pushbullet')
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default" type="button" id="test_pushbullet"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
|
||||
</div>
|
||||
<div class="field-pair result-box">
|
||||
<div class="alert"></div>
|
||||
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
|
||||
<button class="btn btn-default" type="button" id="test_pushbullet" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
|
||||
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div class="alert"></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -426,7 +425,6 @@ jQuery(document).ready(function(){
|
||||
jQuery(this).parents('.col2').find('.col2-cats').hide()
|
||||
}
|
||||
jQuery('form').submit()
|
||||
addRowColor()
|
||||
})
|
||||
jQuery('#email_endjob').change(function() {
|
||||
if(jQuery(this).val() > 0) {
|
||||
@@ -446,8 +444,9 @@ jQuery(document).ready(function(){
|
||||
}
|
||||
// Disable button and get the data
|
||||
jQuery(buttonObj).attr("disabled", "disabled")
|
||||
jQuery(buttonObj).attr("aria-busy", "true")
|
||||
jQuery(buttonObj).find('span').toggleClass('glyphicon-comment glyphicon-refresh spin-glyphicon')
|
||||
var data = { mode: buttonObj.id, apikey: '$apikey', output: 'json' };
|
||||
var data = { mode: buttonObj.id, output: 'json' };
|
||||
jQuery(buttonObj).parents('.section').extractFormDataTo(data);
|
||||
|
||||
// Clear up the box
|
||||
@@ -455,22 +454,23 @@ jQuery(document).ready(function(){
|
||||
|
||||
// Get the request
|
||||
jQuery.ajax({
|
||||
type: "GET",
|
||||
url: "../../api",
|
||||
type: "POST",
|
||||
url: "$url('api')",
|
||||
data: data
|
||||
}).then(function(data) {
|
||||
// Remove disabled and make the box
|
||||
jQuery(buttonObj).removeAttr("disabled")
|
||||
jQuery(buttonObj).attr("aria-busy", "false")
|
||||
jQuery(buttonObj).find('span').toggleClass('glyphicon-comment glyphicon-refresh spin-glyphicon')
|
||||
resultBox.removeClass('alert-success alert-danger').show()
|
||||
if(data.status) {
|
||||
resultBox.addClass('alert-success')
|
||||
resultBox.text('$T('notifications-notesent')')
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-ok-sign"></span> ')
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> ')
|
||||
} else {
|
||||
resultBox.addClass('alert-danger')
|
||||
resultBox.text(data.error)
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ')
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> ')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
<div class="padTable">
|
||||
<a class="main-helplink" href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
|
||||
<p>$T('explain-RSS')</p>
|
||||
<form action="add_rss_feed" method="post" autocomplete="off">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<form data-form="add-rss-feed" action="$url('config/rss/add_rss_feed')" method="post" autocomplete="off">
|
||||
<table class="catTable addRssTable">
|
||||
<tr>
|
||||
<th> </th>
|
||||
@@ -38,8 +37,7 @@
|
||||
<!--#if $rss#-->
|
||||
<div class="section">
|
||||
<div class="padTable">
|
||||
<form action="save_rss_feed" method="post" autocomplete="off">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<form action="$url('config/rss/save_rss_feed')" method="post" autocomplete="off">
|
||||
<table id="subscriptions">
|
||||
<tbody>
|
||||
<!--#set $feeds = sorted($rss.keys(), key=lambda x: x.lower())#-->
|
||||
@@ -75,8 +73,7 @@
|
||||
</form>
|
||||
<!--#if $feeds#-->
|
||||
<br/>
|
||||
<form action="rss_now" method="post" autocomplete="off">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<form action="$url('config/rss/rss_now')" method="post" autocomplete="off">
|
||||
<button type="submit" class="btn btn-default readAll"><span class="glyphicon glyphicon-sort"></span> $T('button-rssNow')</button>
|
||||
</form>
|
||||
<!--#end if#-->
|
||||
@@ -84,8 +81,7 @@
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
<div class="section">
|
||||
<form action="save_rss_rate" method="post" autocomplete="off">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<form action="$url('config/rss/save_rss_rate')" method="post" autocomplete="off">
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
@@ -107,7 +103,7 @@
|
||||
<div class="padTable">
|
||||
<a class="main-helplink" href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
|
||||
<h2 class="nomargin activeRSS">
|
||||
<a href="${root}config/rss/">$T('cmenu-rss')</a> »
|
||||
<a href="$url('config/rss')">$T('cmenu-rss')</a> »
|
||||
$active_feed
|
||||
</h2>
|
||||
<!--#if $error#-->
|
||||
@@ -116,8 +112,7 @@
|
||||
$error
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
<form action="upd_rss_feed" method="post">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<form action="$url('config/rss/upd_rss_feed')" method="post">
|
||||
<input type="hidden" name="feed" value="$active_feed" />
|
||||
<input type="hidden" name="uri" value="$rss[$feed]['uris']" />
|
||||
<table class="catTable">
|
||||
@@ -156,7 +151,8 @@
|
||||
<option value=">"> $T('rss-atleast')</option>
|
||||
<option value="<"> $T('rss-atmost')</option>
|
||||
<option value="F"> $T('rss-from')</option>
|
||||
<option value="F"> $T('rss-from-show') ($T('rss-accept'))</option>
|
||||
<option value="S"> $T('rss-from-show') ($T('rss-accept'))</option>
|
||||
<option value="G"> $T('rss-age')</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
@@ -207,8 +203,7 @@
|
||||
</table>
|
||||
</form>
|
||||
<!-- add new filter -->
|
||||
<form action="upd_rss_filter" method="post">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<form data-form="update-rss-filter" action="$url('config/rss/upd_rss_filter')" method="post">
|
||||
<input type="hidden" name="index" value="$rss[$feed]['filtercount']" />
|
||||
<input type="hidden" name="feed" value="$active_feed" />
|
||||
<table class="catTable">
|
||||
@@ -230,6 +225,7 @@
|
||||
<option value="<"> $T('rss-atmost')</option>
|
||||
<option value="F"> $T('rss-from')</option>
|
||||
<option value="S"> $T('rss-from-show') ($T('rss-accept'))</option>
|
||||
<option value="G"> $T('rss-age')</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
@@ -283,8 +279,7 @@
|
||||
<!--#set $fnum = 0#-->
|
||||
<!--#for $filter in $rss[$feed].filters#-->
|
||||
<!--#set $odd = not $odd#-->
|
||||
<form action="upd_rss_filter" method="post" autocomplete="off">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<form data-form="update-rss-filter" action="$url('config/rss/upd_rss_filter')" method="post" autocomplete="off">
|
||||
<input type="hidden" name="index" value="$fnum" />
|
||||
<input type="hidden" name="feed" value="$active_feed" />
|
||||
<table class="catTable">
|
||||
@@ -306,6 +301,7 @@
|
||||
<option value="<" <!--#if $filter[3]=="<" then 'selected="selected"' else ""#-->> $T('rss-atmost')</option>
|
||||
<option value="F" <!--#if $filter[3]=="F" then 'selected="selected"' else ""#-->> $T('rss-from')</option>
|
||||
<option value="S" <!--#if $filter[3]=="S" then 'selected="selected"' else ""#-->> $T('rss-from-show') ($T('rss-accept'))</option>
|
||||
<option value="G" <!--#if $filter[3]=="G" then 'selected="selected"' else ""#-->> $T('rss-age')</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
@@ -361,137 +357,48 @@
|
||||
</form>
|
||||
<!--#set $fnum = $fnum+1#-->
|
||||
<!--#end for#-->
|
||||
<form action="download_rss_feed" method="post">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<form action="$url('config/rss/download_rss_feed')" method="post">
|
||||
<input type="hidden" name="feed" value="$active_feed" />
|
||||
<div class="padding">
|
||||
<button type="button" class="btn btn-default testFeed" rel="$active_feed"><span class="glyphicon glyphicon-sort"></span> $T('button-preFeed')</button>
|
||||
<button type="submit" class="btn btn-default Save"><span class="glyphicon glyphicon-forward"></span> $T('button-forceFeed')</button>
|
||||
<button type="button" class="btn btn-default cleanFeed"><span class="glyphicon glyphicon-trash"></span> $T('button-clear') $T('rss-done')</button>
|
||||
<!--#if $evalButton#-->
|
||||
<button type="button" class="btn btn-default evalFeed" rel="$active_feed"><span class="glyphicon glyphicon-ok-circle"></span> $T('button-evalFeed')</button>
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<div style="padding-left: 10px; border-bottom: 1px solid #DFDEDE;">
|
||||
<ul class="tabs">
|
||||
<li class="active"><a href="#rss-tab-matched" data-toggle="tab">$T('rss-matched') <span class="count"><!--#echo len($matched)#--></span></a></li>
|
||||
<li><a href="#rss-tab-not-matched">$T('rss-notMatched') <span class="count"><!--#echo len($unmatched)#--></span></a></li>
|
||||
<li><a href="#rss-tab-done">$T('rss-done') <span class="count"><!--#echo len($downloaded)#--></span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade in active padTable" id="rss-tab-matched">
|
||||
<!--#if $matched#-->
|
||||
<table class="catTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="no-sort">$T('link-download')</th>
|
||||
<th>$T('rss-filter')</th>
|
||||
<th>$T('size')</th>
|
||||
<th width="60%">$T('sort-title')</th>
|
||||
<th>$T('category')</th>
|
||||
<th class="default-sort">$T('nzo-age')</th>
|
||||
<th>$T('source')</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!--#for $job in $matched#-->
|
||||
<tr class="infoTableSeperator">
|
||||
<td>
|
||||
<form action="download" method="get">
|
||||
<input type="hidden" value="$active_feed" name="feed" />
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="url" value="$job['url']" />
|
||||
<input type="hidden" name="nzbname" value="$job['nzbname']" />
|
||||
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> $T('link-download')</button>
|
||||
</form>
|
||||
</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>
|
||||
<!--#else#-->
|
||||
<a class="favicon source-icon" href="$job['infourl']" target="_blank" style="background-image: url(//$job['baselink']/favicon.ico);" data-domain="$job['baselink']"></a>
|
||||
<!--#end if#-->
|
||||
</td>
|
||||
</tr>
|
||||
<!--#end for#-->
|
||||
</table>
|
||||
<!--#else#-->
|
||||
$T('none')
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
<div class="tab-pane padTable" id="rss-tab-not-matched">
|
||||
<!--#if $unmatched#-->
|
||||
<table class="catTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="no-sort">$T('link-download')</th>
|
||||
<th>$T('rss-filter')</th>
|
||||
<th>$T('size')</th>
|
||||
<th width="60%">$T('sort-title')</th>
|
||||
<th>$T('category')</th>
|
||||
<th class="default-sort">$T('nzo-age')</th>
|
||||
<th>$T('source')</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!--#for $job in $unmatched#-->
|
||||
<tr class="infoTableSeperator">
|
||||
<td>
|
||||
<form action="download" method="get">
|
||||
<input type="hidden" value="$active_feed" name="feed" />
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="url" value="$job['url']" />
|
||||
<input type="hidden" name="nzbname" value="$job['nzbname']" />
|
||||
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> $T('link-download')</button>
|
||||
</form>
|
||||
</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>
|
||||
<!--#else#-->
|
||||
<a class="favicon source-icon" href="$job['infourl']" target="_blank" style="background-image: url(//$job['baselink']/favicon.ico);" data-domain="$job['baselink']"></a>
|
||||
<!--#end if#-->
|
||||
</td>
|
||||
</tr>
|
||||
<!--#end for#-->
|
||||
</table>
|
||||
<!--#else#-->
|
||||
$T('none')
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
<div class="tab-pane padTable" id="rss-tab-done">
|
||||
<!--#if $downloaded#-->
|
||||
<form action="clean_rss_jobs" method="post">
|
||||
<input type="hidden" value="$active_feed" name="feed" />
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#rss-tab-matched" data-toggle="tab">$T('rss-matched') <span class="count"><!--#echo len($matched)#--></span></a></li>
|
||||
<li><a href="#rss-tab-not-matched">$T('rss-notMatched') <span class="count"><!--#echo len($unmatched)#--></span></a></li>
|
||||
<li><a href="#rss-tab-done">$T('rss-done') <span class="count"><!--#echo len($downloaded)#--></span></a></li>
|
||||
</ul>
|
||||
<div class="section">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade in active padTable" id="rss-tab-matched">
|
||||
<!--#if $matched#-->
|
||||
<table class="catTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="default-sort">$T('rss-added')</th>
|
||||
<th class="no-sort">$T('link-download')</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 class="default-sort">$T('nzo-age')</th>
|
||||
<th>$T('source')</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!--#for $job in $downloaded#-->
|
||||
<!--#for $job in $matched#-->
|
||||
<tr class="infoTableSeperator">
|
||||
<td data-sort-value="$job['time_downloaded_ms']">$job['time_downloaded']</td>
|
||||
<td>
|
||||
<form data-form="download-rss-job" action="$url('config/rss/download')" method="post">
|
||||
<input type="hidden" value="$active_feed" name="feed" />
|
||||
<input type="hidden" name="url" value="$job['url']" />
|
||||
<input type="hidden" name="nzbname" value="$job['nzbname']" />
|
||||
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> $T('link-download')</button>
|
||||
</form>
|
||||
</td>
|
||||
<td>$job['rule'] $job['skip']</td>
|
||||
<td data-sort-value="$job['size']">$job['size_units']</td>
|
||||
<td>$job['title']</td>
|
||||
@@ -507,22 +414,104 @@
|
||||
</tr>
|
||||
<!--#end for#-->
|
||||
</table>
|
||||
</form>
|
||||
<!--#else#-->
|
||||
<!--#else#-->
|
||||
$T('none')
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
<div class="tab-pane padTable" id="rss-tab-not-matched">
|
||||
<!--#if $unmatched#-->
|
||||
<table class="catTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="no-sort">$T('link-download')</th>
|
||||
<th>$T('rss-filter')</th>
|
||||
<th>$T('size')</th>
|
||||
<th width="60%">$T('sort-title')</th>
|
||||
<th>$T('category')</th>
|
||||
<th class="default-sort">$T('nzo-age')</th>
|
||||
<th>$T('source')</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!--#for $job in $unmatched#-->
|
||||
<tr class="infoTableSeperator">
|
||||
<td>
|
||||
<form data-form="download-rss-job" action="$url('config/rss/download')" method="post">
|
||||
<input type="hidden" value="$active_feed" name="feed" />
|
||||
<input type="hidden" name="url" value="$job['url']" />
|
||||
<input type="hidden" name="nzbname" value="$job['nzbname']" />
|
||||
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> $T('link-download')</button>
|
||||
</form>
|
||||
</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>
|
||||
<!--#else#-->
|
||||
<a class="favicon source-icon" href="$job['infourl']" target="_blank" style="background-image: url(//$job['baselink']/favicon.ico);" data-domain="$job['baselink']"></a>
|
||||
<!--#end if#-->
|
||||
</td>
|
||||
</tr>
|
||||
<!--#end for#-->
|
||||
</table>
|
||||
<!--#else#-->
|
||||
$T('none')
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
<div class="tab-pane padTable" id="rss-tab-done">
|
||||
<!--#if $downloaded#-->
|
||||
<form action="$url('config/rss/clean_rss_jobs')" method="post">
|
||||
<input type="hidden" value="$active_feed" name="feed" />
|
||||
<table class="catTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="default-sort">$T('rss-added')</th>
|
||||
<th>$T('rss-filter')</th>
|
||||
<th>$T('size')</th>
|
||||
<th width="60%">$T('sort-title')</th>
|
||||
<th>$T('category')</th>
|
||||
<th>$T('nzo-age')</th>
|
||||
<th>$T('source')</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!--#for $job in $downloaded#-->
|
||||
<tr class="infoTableSeperator">
|
||||
<td data-sort-value="$job['time_downloaded_ms']">$job['time_downloaded']</td>
|
||||
<td>$job['rule'] $job['skip']</td>
|
||||
<td data-sort-value="$job['size']">$job['size_units']</td>
|
||||
<td>$job['title']</td>
|
||||
<td>$job['cat']</td>
|
||||
<td data-sort-value="$job['age_ms']">$job['age']</td>
|
||||
<td data-sort-value="$job['baselink']" title="$job['baselink']">
|
||||
<!--#if not $job['infourl']#-->
|
||||
<div class="favicon source-icon" style="background-image: url(//$job['baselink']/favicon.ico);" data-domain="$job['baselink']"></div>
|
||||
<!--#else#-->
|
||||
<a class="favicon source-icon" href="$job['infourl']" target="_blank" style="background-image: url(//$job['baselink']/favicon.ico);" data-domain="$job['baselink']"></a>
|
||||
<!--#end if#-->
|
||||
</td>
|
||||
</tr>
|
||||
<!--#end for#-->
|
||||
</table>
|
||||
</form>
|
||||
<!--#else#-->
|
||||
$T('none')
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
</div>
|
||||
<!-- /colmask -->
|
||||
|
||||
<form method="post" action="save_rss_feed" class="modal fade" id="rss_edit_modal">
|
||||
<form method="post" action="$url('config/rss/save_rss_feed')" class="modal fade" id="rss_edit_modal" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="rss-edit-modal-title">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">$T('Edit') <span id="feed_edit_name_label"></span></h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="rss-edit-modal-title">$T('Edit') <span id="feed_edit_name_label"></span></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
@@ -535,7 +524,6 @@
|
||||
<span class="help-block">$T('addMultipleFeeds')</span>
|
||||
</div>
|
||||
<input type="hidden" name="feed" id="feed_edit_old_name" />
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-danger" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> $T('cancel')</button>
|
||||
@@ -545,7 +533,7 @@
|
||||
</div><!-- /.modal-dialog -->
|
||||
</form><!-- /.modal -->
|
||||
|
||||
<script type="text/javascript" src="${root}staticcfg/js/jquery.tablesort.min.js"></script>
|
||||
<script type="text/javascript" src="$url('staticcfg/js/jquery.tablesort.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript">
|
||||
function urlencode(str) {
|
||||
return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
|
||||
@@ -564,7 +552,7 @@ jQuery(document).ready(function(){
|
||||
}
|
||||
})
|
||||
|
||||
jQuery('.tabs a').click(function (e) {
|
||||
jQuery('.nav-tabs a').click(function (e) {
|
||||
e.preventDefault()
|
||||
jQuery(this).tab('show')
|
||||
})
|
||||
@@ -589,8 +577,8 @@ jQuery(document).ready(function(){
|
||||
var whichFeed = jQuery(this).attr("rel");
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "del_rss_feed",
|
||||
data: {feed: whichFeed, apikey: "$apikey" }
|
||||
url: "$url('config/rss/del_rss_feed')",
|
||||
data: {feed: whichFeed }
|
||||
}).done(function( msg ) {
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
@@ -604,8 +592,8 @@ jQuery(document).ready(function(){
|
||||
var whichFeed = jQuery(this).attr("rel");
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "toggle_rss_feed",
|
||||
data: {feed: whichFeed, apikey: "$apikey" }
|
||||
url: "$url('config/rss/toggle_rss_feed')",
|
||||
data: {feed: whichFeed }
|
||||
}).done(function() {
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
@@ -615,7 +603,7 @@ jQuery(document).ready(function(){
|
||||
});
|
||||
|
||||
// Only the Accept filter needs all the options
|
||||
jQuery('form[action="upd_rss_filter"]').find('select[name="filter_type"]').change(function() {
|
||||
jQuery('form[data-form="update-rss-filter"]').find('select[name="filter_type"]').change(function() {
|
||||
jQuery(this).parent().parent().find('select:not([name="filter_type"])').attr('disabled', jQuery(this).val() !== "A" && jQuery(this).val() !== "S")
|
||||
})
|
||||
// Trigger on-load for all
|
||||
@@ -644,8 +632,8 @@ jQuery(document).ready(function(){
|
||||
var whichFeed = jQuery(this).attr("rel");
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "test_rss_feed",
|
||||
data: {feed: whichFeed, apikey: "$apikey" }
|
||||
url: "$url('config/rss/test_rss_feed')",
|
||||
data: {feed: whichFeed }
|
||||
}).done(function( msg ) {
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
@@ -657,21 +645,21 @@ jQuery(document).ready(function(){
|
||||
jQuery('.cleanFeed').click(function(){
|
||||
setActiveIcon(this)
|
||||
var theForm = jQuery(this).closest("form");
|
||||
theForm.attr("action", "clean_rss_jobs").submit();
|
||||
theForm.attr("action", "$url('config/rss/clean_rss_jobs')").submit();
|
||||
});
|
||||
|
||||
jQuery('.evalFeed').click(function(){
|
||||
setActiveIcon(this)
|
||||
var theForm = jQuery(this).closest("form");
|
||||
theForm.attr("action", "eval_rss_feed").submit();
|
||||
theForm.attr("action", "$url('config/rss/eval_rss_feed')").submit();
|
||||
});
|
||||
|
||||
jQuery('.delFilter').click(function(){
|
||||
var theForm = jQuery(this).closest("form");
|
||||
theForm.attr("action", "del_rss_filter").submit();
|
||||
theForm.attr("action", "$url('config/rss/del_rss_filter')").submit();
|
||||
});
|
||||
|
||||
jQuery('form[action="download"]').ajaxForm({
|
||||
jQuery('form[data-form="download-rss-job"]').ajaxForm({
|
||||
datatype: 'json',
|
||||
beforeSubmit: function (_, form) {
|
||||
jQuery(form).find('button').attr("disabled", "disabled")
|
||||
|
||||
@@ -17,17 +17,16 @@ else:
|
||||
<div class="col2">
|
||||
<h3>$T('addSchedule') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div><!-- /col2 -->
|
||||
<form action="addSchedule" method="post" autocomplete="off">
|
||||
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
|
||||
<form data-form="add-schedule" action="$url('config/scheduling/add_schedule')" method="post" autocomplete="off">
|
||||
<div class="col1">
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="hour">$T('hour').capitalize() : $T('minute').capitalize()</label>
|
||||
<select name="hour" id="hour">
|
||||
<select name="hour" id="hour" aria-label="$T('hour').capitalize()">
|
||||
<!--#for $i in range(24)#-->
|
||||
<option value="$i" <!--#if hour == i then 'selected="selected"' else ""#--> > $str($i).zfill(2) </option>
|
||||
<!--#end for#-->
|
||||
</select> <b>:</b> <select name="minute" id="minute">
|
||||
</select> <b>:</b> <select name="minute" id="minute" aria-label="$T('minute').capitalize()">
|
||||
<!--#for $i in range(60)#-->
|
||||
<option value="$i"> $str($i).zfill(2) </option>
|
||||
<!--#end for#-->
|
||||
@@ -90,13 +89,12 @@ else:
|
||||
<!--#set $odd = True#-->
|
||||
<!--#for $schednum, $line in enumerate($schedlines)#-->
|
||||
<!--#set $odd = not $odd#-->
|
||||
<form action="delSchedule" method="post">
|
||||
<input type="hidden" name="apikey" value="$apikey"/>
|
||||
<input type="hidden" name="line" id="line" value="$line"/>
|
||||
<form data-form="del-schedule" action="$url('config/scheduling/del_schedule')" method="post">
|
||||
<input type="hidden" name="line" value="$line"/>
|
||||
<div class="field-pair infoTableSeperator <!--#if $odd then "" else " alt"#-->">
|
||||
<input type="checkbox" name="schedenabled" value="$line" <!--#if int($taskinfo[$schednum][5]) > 0 then 'checked="checked"' else ""#-->>
|
||||
<button class="btn btn-default float-left"><span class="glyphicon glyphicon-trash"></span></button>
|
||||
<div class="scheduleEntry">
|
||||
<input type="checkbox" name="schedenabled" value="$line" aria-label="$T('enabled')" aria-describedby="schedule-description-$schednum" <!--#if int($taskinfo[$schednum][5]) > 0 then 'checked="checked"' else ""#-->>
|
||||
<button class="btn btn-default float-left" type="submit" aria-label="$T('nzo-delete')" aria-describedby="schedule-description-$schednum"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button>
|
||||
<div class="scheduleEntry" id="schedule-description-$schednum">
|
||||
<span class="time">$taskinfo[$schednum][1]:$taskinfo[$schednum][2]</span><span class="frequency">$taskinfo[$schednum][3]</span> <span class="darkred">$taskinfo[$schednum][4]</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -136,8 +134,8 @@ else:
|
||||
jQuery('[name="schedenabled"]').click(function() {
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "toggleSchedule",
|
||||
data: {line: jQuery(this).val(), apikey: "$apikey" }
|
||||
url: "$url('config/scheduling/toggle_schedule')",
|
||||
data: {line: jQuery(this).val() }
|
||||
}).done(function() {
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
|
||||
@@ -40,14 +40,12 @@
|
||||
<h3>$T('addServer') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
|
||||
</div>
|
||||
<div class="col1">
|
||||
<form action="addServer" method="post" autocomplete="off" onsubmit="removeObfuscation();">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<form data-form="add-server" action="$url('config/server/add_server')" method="post" autocomplete="off">
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="enable">$T('srv-enable')</label>
|
||||
<input type="checkbox" name="enable" id="enable" value="1" checked="checked" />
|
||||
<span class="desc">$T('srv-enable')</span>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="displayname">$T('srv-displayname')</label>
|
||||
@@ -77,7 +75,7 @@
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="connections">$T('srv-connections')</label>
|
||||
<input type="number" name="connections" id="connections" min="1" max="500" value="8" required />
|
||||
<input type="number" name="connections" id="connections" min="1" max="500" value="16" required />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="priority">$T('srv-priority')</label>
|
||||
@@ -139,11 +137,12 @@
|
||||
</div>
|
||||
<div class="field-pair no-field-pair-bg">
|
||||
<button class="btn btn-default addNewServer" disabled data-toggle="tooltip" data-placement="top" title="$T('wizard-test-server-required')"><span class="glyphicon glyphicon-plus"></span> $T('button-addServer')</button>
|
||||
<button class="btn btn-default testServer" type="button"><span class="glyphicon glyphicon-sort"></span> $T('button-testServer')</button>
|
||||
</div>
|
||||
<div class="field-pair result-box">
|
||||
<div class="alert"></div>
|
||||
<button class="btn btn-default testServer" type="button" aria-busy="false"><span class="glyphicon glyphicon-sort" aria-hidden="true"></span> $T('button-testServer')</button>
|
||||
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div class="alert"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
@@ -153,11 +152,9 @@
|
||||
<!--#set $cur_prio_color = -1 #-->
|
||||
<!--#set $last_prio = -1 #-->
|
||||
<!--#for $cur, $server in enumerate($servers) #-->
|
||||
<form action="saveServer" method="post" class="fullform" autocomplete="off">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<form action="$url('config/server/save_server')" method="post" class="fullform" autocomplete="off">
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<input type="hidden" name="server" value="$server['name']" />
|
||||
<input type="hidden" name="ajax" value=1 />
|
||||
|
||||
<div class="section <!--#if int($server['enable']) == 0 then 'server-disabled' else ""#-->">
|
||||
<div class="col2 <!--#if int($server['enable']) == 0 then 'server-disabled' else ""#-->">
|
||||
@@ -276,15 +273,16 @@
|
||||
</div>
|
||||
<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 testServer" type="button" aria-busy="false"><span class="glyphicon glyphicon-sort" aria-hidden="true"></span> $T('button-testServer')</button>
|
||||
<button class="btn btn-default delServer"><span class="glyphicon glyphicon-trash"></span> $T('button-delServer')</button>
|
||||
</div>
|
||||
<div class="field-pair result-box">
|
||||
<div class="alert"></div>
|
||||
|
||||
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div class="alert"></div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="col1" style="display:block;">
|
||||
<div class="col1 padding" style="display:block;">
|
||||
<!--#if 'amounts' in $server#-->
|
||||
<div class="server-amounts-text">
|
||||
<p>
|
||||
@@ -327,8 +325,8 @@
|
||||
<!--#end for#-->
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="${root}staticcfg/js/chartist.min.js"></script>
|
||||
<script type="text/javascript" src="${root}staticcfg/js/filesize.min.js"></script>
|
||||
<script type="text/javascript" src="$url('staticcfg/js/chartist.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('staticcfg/js/filesize.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript">
|
||||
// Standardize chart options
|
||||
var chartOptions = {
|
||||
@@ -479,11 +477,9 @@
|
||||
// Initialize tooltips
|
||||
jQuery('[data-toggle="tooltip"]').tooltip()
|
||||
|
||||
// Reload form in case we change items that make the servers appear different
|
||||
// Reload the page after saving in case we change items that make the servers appear different
|
||||
jQuery('input[name="priority"], input[name="displayname"], textarea[name="notes"]').on('change', function(event) {
|
||||
var parentForm = jQuery(event.target).parents("form")
|
||||
parentForm.unbind("submit")
|
||||
parentForm.find('input[name="ajax"]').val('')
|
||||
jQuery(event.target).parents("form").attr("data-reload-on-save", "")
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -517,14 +513,10 @@
|
||||
// Recalculate the charts if changed while details were open
|
||||
showCharts()
|
||||
}
|
||||
// Add coloring
|
||||
addRowColor()
|
||||
});
|
||||
|
||||
jQuery('#addServerButton').click(function(){
|
||||
jQuery('#addServerContent').show();
|
||||
// Add coloring
|
||||
addRowColor()
|
||||
});
|
||||
|
||||
jQuery('[name="ssl"]').click(function() {
|
||||
@@ -552,28 +544,31 @@
|
||||
var theButton = jQuery(this)
|
||||
var resultBox = theButton.parents('.col1').find('.result-box .alert');
|
||||
theButton.attr("disabled", "disabled")
|
||||
theButton.attr("aria-busy", "true")
|
||||
theButton.find('span').toggleClass('glyphicon-sort glyphicon-refresh spin-glyphicon')
|
||||
resultBox.removeClass('alert-success alert-danger').addClass('alert-info').html("$T('srv-testing')").show()
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "../../api",
|
||||
url: "$url('api')",
|
||||
data: "mode=config&name=test_server&" + jQuery(this).parents('form:first').serialize()
|
||||
}).then(function(data) {
|
||||
// Let's replace the link
|
||||
msg = data.value.message.replace('https://sabnzbd.org/certificate-errors', '<a href="https://sabnzbd.org/certificate-errors" class="alert-link" target="_blank">https://sabnzbd.org/certificate-errors</a>')
|
||||
msg = msg.replace('-', '<br>')
|
||||
// Fill the box and enable the button
|
||||
resultBox.removeClass('alert-success alert-danger').show()
|
||||
resultBox.removeClass('alert-info alert-success alert-danger').show()
|
||||
resultBox.html(msg)
|
||||
theButton.removeAttr("disabled")
|
||||
theButton.attr("aria-busy", "false")
|
||||
theButton.find('span').toggleClass('glyphicon-sort glyphicon-refresh spin-glyphicon')
|
||||
|
||||
// Success or not?
|
||||
if(data.value.result) {
|
||||
resultBox.addClass('alert-success')
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-ok-sign"></span> ')
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> ')
|
||||
|
||||
// Allow adding the new server if we are in the new-server section
|
||||
if(theButton.parents("form[action='addServer']").length) {
|
||||
if(theButton.parents("form[data-form='add-server']").length) {
|
||||
jQuery(".addNewServer").removeAttr("disabled")
|
||||
jQuery(".addNewServer").removeAttr("data-toggle")
|
||||
jQuery(".addNewServer").removeAttr("title")
|
||||
@@ -581,10 +576,10 @@
|
||||
}
|
||||
} else {
|
||||
resultBox.addClass('alert-danger')
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ')
|
||||
resultBox.prepend('<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> ')
|
||||
|
||||
// Disable the adding of new server, just to be sure
|
||||
if(theButton.parents("form[action='addServer']").length) {
|
||||
if(theButton.parents("form[data-form='add-server']").length) {
|
||||
jQuery(".addNewServer").attr("disabled", "disabled")
|
||||
jQuery(".addNewServer").attr("data-toggle", "tooltip")
|
||||
jQuery(".addNewServer").attr("data-placement", "top")
|
||||
@@ -595,9 +590,34 @@
|
||||
});
|
||||
});
|
||||
|
||||
jQuery('.addNewServer').click(function(event){
|
||||
event.preventDefault()
|
||||
removeObfuscation()
|
||||
var theButton = jQuery(this)
|
||||
var resultBox = theButton.parents('.col1').find('.result-box .alert')
|
||||
theButton.attr("disabled", "disabled")
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "$url('config/server/add_server')",
|
||||
data: theButton.parents('form:first').serialize()
|
||||
}).then(function(data) {
|
||||
if(data.status) {
|
||||
// Success — reload to show the new server
|
||||
formWasSubmitted = true
|
||||
formHasChanged = false
|
||||
location.reload()
|
||||
} else {
|
||||
// Show error in the result box
|
||||
resultBox.removeClass('alert-success').addClass('alert-danger').show()
|
||||
resultBox.html('<span class="glyphicon glyphicon-exclamation-sign"></span> ' + data.error)
|
||||
theButton.removeAttr("disabled")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
jQuery('.delServer').click(function(){
|
||||
if( confirm("$T('confirm')") ) {
|
||||
jQuery(this).parents('form:first').attr('action','delServer').submit();
|
||||
jQuery(this).parents('form:first').attr('action',"$url('config/server/delete_server')").submit();
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
formHasChanged = false;
|
||||
@@ -608,7 +628,7 @@
|
||||
|
||||
jQuery('.clrServer').click(function(){
|
||||
if( confirm("$T('confirm')") ) {
|
||||
jQuery(this).parents('form:first').attr('action','clrServer').submit();
|
||||
jQuery(this).parents('form:first').attr('action',"$url('config/server/clear_server')").submit();
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
formHasChanged = false;
|
||||
@@ -621,8 +641,8 @@
|
||||
var whichServer = jQuery(this).attr("name");
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "toggleServer",
|
||||
data: {server: whichServer, apikey: "$apikey" }
|
||||
url: "$url('config/server/toggle_server')",
|
||||
data: {server: whichServer }
|
||||
}).done(function() {
|
||||
// Let us leave!
|
||||
formWasSubmitted = true;
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
<!--#set $selected_types = ["0"] if not len($selected_types) else $selected_types #-->
|
||||
<!-- SORTER $cur -->
|
||||
<div class="section <!--#if $cur != 0#-->sorter<!--#end if#-->" id="sorter_$cur" <!--#if $cur == 0#-->style="display: none;"<!--#end if#-->>
|
||||
<form action="save_sorter" method="post" autocomplete="off" <!--#if $cur != 0#-->class="sorting-row"<!--#end if#-->>
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<form action="$url('config/sorting/save_sorter')" method="post" autocomplete="off" <!--#if $cur != 0#-->class="sorting-row"<!--#end if#-->>
|
||||
<input type="hidden" name="order" value="$slot.order" />
|
||||
<input type="hidden" value="$slot.name" name="name" />
|
||||
<!--#if $cur == 0#-->
|
||||
@@ -347,8 +346,7 @@
|
||||
<div class="section align-center sorting-quick-setup">
|
||||
<h3>$T('sort-quick-add'):</h3>
|
||||
<!--#if "tv" in $categories#-->
|
||||
<form action="save_sorter" method="post" autocomplete="off">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<form action="$url('config/sorting/save_sorter')" method="post" autocomplete="off">
|
||||
<input type="hidden" name="order" value="0" />
|
||||
<input type="hidden" name="is_active" value="1" />
|
||||
<input type="hidden" name="name" value="">
|
||||
@@ -366,8 +364,7 @@
|
||||
</form>
|
||||
<!--#end if#-->
|
||||
<!--#if "movies" in $categories#-->
|
||||
<form action="save_sorter" method="post" autocomplete="off">
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<form action="$url('config/sorting/save_sorter')" method="post" autocomplete="off">
|
||||
<input type="hidden" name="order" value="0" />
|
||||
<input type="hidden" name="is_active" value="1" />
|
||||
<input type="hidden" name="name" value="">
|
||||
@@ -388,7 +385,7 @@
|
||||
</div>
|
||||
<!--#end if#-->
|
||||
</div>
|
||||
<script type="text/javascript" src="${root}staticcfg/js/jquery-ui.min.js"></script>
|
||||
<script type="text/javascript" src="$url('staticcfg/js/jquery-ui.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript">
|
||||
// http://stackoverflow.com/questions/2219924/
|
||||
var typewatch = (function(){
|
||||
@@ -414,13 +411,12 @@
|
||||
typewatch(function () {
|
||||
jQuery.ajax({
|
||||
type: "GET",
|
||||
url: "../../api",
|
||||
url: "$url('api')",
|
||||
data: {
|
||||
mode: 'eval_sort',
|
||||
job_name: jQuery('#preview_name_' + sort_nr).val(),
|
||||
sort_string: preview_sort_string,
|
||||
multipart_label: jQuery('#multipart_label_' + sort_nr).val(),
|
||||
apikey: '$apikey',
|
||||
output: 'json'
|
||||
},
|
||||
success: function(data) {
|
||||
@@ -437,13 +433,11 @@
|
||||
jQuery(document).ready(function() {
|
||||
jQuery('.delSorter').click(function() {
|
||||
var theForm = jQuery(this).closest("form");
|
||||
theForm.attr("action", "delete").submit();
|
||||
theForm.attr("action", "$url('config/sorting/delete')").submit();
|
||||
});
|
||||
|
||||
jQuery('.addSorter').click(function(){
|
||||
jQuery('#sorter_0').toggle();
|
||||
// Add coloring
|
||||
addRowColor()
|
||||
});
|
||||
|
||||
jQuery('.showSorter').click(function () {
|
||||
@@ -455,8 +449,6 @@
|
||||
} else {
|
||||
theSwitch.html(theSwitch.html().replace("$T('hideDetails')", "$T('showDetails')"));
|
||||
}
|
||||
// Add coloring
|
||||
addRowColor()
|
||||
});
|
||||
|
||||
// Make the configured sorters sortable
|
||||
@@ -498,8 +490,8 @@
|
||||
var data = {}
|
||||
jQuery(elm).extractFormDataTo(data);
|
||||
jQuery.ajax({
|
||||
type: "GET",
|
||||
url: window.location.pathname + 'save_sorter',
|
||||
type: "POST",
|
||||
url: "$url('config/sorting/save_sorter')",
|
||||
data: data,
|
||||
async: false // To prevent race-conditions when updating sorters
|
||||
})
|
||||
@@ -513,8 +505,8 @@
|
||||
var whichSorter = jQuery(this).attr("rel");
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "toggle_sorter",
|
||||
data: {sorter: whichSorter, apikey: "$apikey" }
|
||||
url: "$url('config/sorting/toggle_sorter')",
|
||||
data: {sorter: whichSorter }
|
||||
}).done(function() {
|
||||
formWasSubmitted = true;
|
||||
formHasChanged = false;
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<div class="colmask">
|
||||
<form action="saveSpecial" method="post" autocomplete="off">
|
||||
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
|
||||
<form action="$url('config/special/save')" method="post" class="fullform" autocomplete="off">
|
||||
<div class="padTable">
|
||||
<h4 class="darkred nomargin">$T('explain-special')</h4>
|
||||
</div>
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
<input type="checkbox" id="advanced-settings-button" name="advanced-settings-button"> $T('button-advanced')
|
||||
</label>
|
||||
</div>
|
||||
<form action="saveSwitches" method="post" name="fullform" class="fullform" autocomplete="off">
|
||||
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
|
||||
<input type="hidden" id="ajax" name="ajax" value="1" />
|
||||
<form action="$url('config/switches/save')" method="post" class="fullform" autocomplete="off">
|
||||
<input type="hidden" name="output" value="json" />
|
||||
<div class="section advanced-settings">
|
||||
<div class="col2">
|
||||
@@ -152,6 +150,7 @@
|
||||
<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="remaining_bytes asc" <!--#if $auto_sort == "remaining_bytes asc" then 'selected="selected"' else ""#--> >$T('Glitter-sortRemainingBytesAsc')</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>
|
||||
@@ -261,7 +260,7 @@
|
||||
<div class="field-pair">
|
||||
<label class="config" for="history_retention_option">$T('opt-history_retention')</label>
|
||||
<select name="history_retention_option" id="history_retention_option">
|
||||
<option value="all" <!--#if $auto_sort == "all" then 'selected="selected"' else ""#-->>$T('history_retention-all')</option>
|
||||
<option value="all" <!--#if $history_retention_option == "all" then 'selected="selected"' else ""#-->>$T('history_retention-all')</option>
|
||||
<option value="number-archive" <!--#if $history_retention_option == "number-archive" then 'selected="selected"' else ""#-->>$T('history_retention-number-archive')</option>
|
||||
<option value="number-delete" <!--#if $history_retention_option == "number-delete" then 'selected="selected"' else ""#-->>$T('history_retention-number-delete')</option>
|
||||
<option value="days-archive" <!--#if $history_retention_option == "days-archive" then 'selected="selected"' else ""#-->>$T('history_retention-days-archive')</option>
|
||||
@@ -394,9 +393,9 @@ jQuery(document).ready(function() {
|
||||
|
||||
// Send request
|
||||
jQuery.ajax({
|
||||
type: "GET",
|
||||
url: "../../api",
|
||||
data: "mode=set_config_default&apikey=${apikey}&output=json&keyword=" + key_container.join('&keyword=')
|
||||
type: "POST",
|
||||
url: "$url('api')",
|
||||
data: "mode=set_config_default&output=json&keyword=" + key_container.join('&keyword=')
|
||||
}).then(function(data) {
|
||||
// Reload page
|
||||
document.location = document.location
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="$active_lang">
|
||||
<html lang="$active_lang" data-color-scheme="$color_scheme">
|
||||
<head>
|
||||
<title>SABnzbd - $T('login')</title>
|
||||
|
||||
@@ -7,44 +7,40 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, maximum-scale=1" />
|
||||
<meta name="apple-mobile-web-app-title" content="SABnzbd" />
|
||||
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="../staticcfg/ico/apple-touch-icon-76x76-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="../staticcfg/ico/apple-touch-icon-120x120-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="../staticcfg/ico/apple-touch-icon-152x152-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="../staticcfg/ico/apple-touch-icon-180x180-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="../staticcfg/ico/android-192x192.png" />
|
||||
<link rel="shortcut icon" href="../staticcfg/ico/favicon.ico?v=$version" />
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="$url('staticcfg/ico/apple-touch-icon-76x76-precomposed.png', v=$cache_buster)" />
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="$url('staticcfg/ico/apple-touch-icon-120x120-precomposed.png', v=$cache_buster)" />
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="$url('staticcfg/ico/apple-touch-icon-152x152-precomposed.png', v=$cache_buster)" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="$url('staticcfg/ico/apple-touch-icon-180x180-precomposed.png', v=$cache_buster)" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="$url('staticcfg/ico/android-192x192.png', v=$cache_buster)" />
|
||||
<link rel="shortcut icon" href="$url('staticcfg/ico/favicon.ico', v=$cache_buster)" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="../staticcfg/bootstrap/css/bootstrap.min.css?v=$version" />
|
||||
<link rel="stylesheet" type="text/css" href="../staticcfg/css/login.css?v=$version" />
|
||||
<!--#if $color_scheme not in ('Light', '') #-->
|
||||
<link rel="stylesheet" type="text/css" href="../staticcfg/css/${color_scheme}.css?v=$version"/>
|
||||
<!--#end if#-->
|
||||
<link rel="stylesheet" type="text/css" href="$url('staticcfg/bootstrap/css/bootstrap.min.css', v=$cache_buster)" />
|
||||
<link rel="stylesheet" type="text/css" href="$url('staticcfg/css/login.css', v=$cache_buster)" />
|
||||
|
||||
<script type="text/javascript" src="../staticcfg/js/jquery-3.5.1.min.js?v=$version"></script>
|
||||
<script type="text/javascript" src="../staticcfg/bootstrap/js/bootstrap.min.js?v=$version"></script>
|
||||
<script type="text/javascript" src="$url('staticcfg/js/jquery-3.7.1.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('staticcfg/bootstrap/js/bootstrap.min.js', v=$cache_buster)"></script>
|
||||
</head>
|
||||
<html>
|
||||
<body>
|
||||
<div class="account-wall">
|
||||
<div class="text-center logo-header">
|
||||
<!--#include $webdir + "/staticcfg/images/logo-full.svg"#-->
|
||||
<a href="https://sabnzbd.org/wiki/faq#why-login" target="_blank">
|
||||
<span class="glyphicon glyphicon-question-sign"></span>
|
||||
<a href="https://sabnzbd.org/wiki/faq#why-login" target="_blank" aria-label="$T('menu-help')">
|
||||
<span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span>
|
||||
</a>
|
||||
</div>
|
||||
<form class="form-signin" action="./" method="post">
|
||||
<form class="form-signin" action="./login" method="post">
|
||||
<!--#if $error#-->
|
||||
<div class="alert alert-danger" role="alert">$error</div>
|
||||
<!--#end if#-->
|
||||
|
||||
<input type="text" class="form-control" name="username" placeholder="$T('srv-username')" autocomplete="username" required autofocus>
|
||||
<input type="password" class="form-control" name="password" placeholder="$T('srv-password')" autocomplete="current-password" required>
|
||||
<input type="text" class="form-control" name="username" placeholder="$T('srv-username')" aria-label="$T('srv-username')" autocomplete="username" required autofocus>
|
||||
<input type="password" class="form-control" name="password" placeholder="$T('srv-password')" aria-label="$T('srv-password')" autocomplete="current-password" required>
|
||||
|
||||
<button class="btn btn-default"><span class="glyphicon glyphicon-circle-arrow-right"></span> $T('login') </button>
|
||||
|
||||
<div class="checkbox text-center" data-toggle="tooltip" data-placement="bottom" title="$T('explain-sessionExpire')">
|
||||
<div class="text-center" data-toggle="tooltip" data-placement="bottom" title="$T('explain-sessionExpire')">
|
||||
<label>
|
||||
<input type="checkbox" name="remember_me" value="1"> $T('rememberme')
|
||||
$T('rememberme') <input type="checkbox" name="remember_me" value="1">
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
@@ -63,4 +59,4 @@
|
||||
} catch(err) { }
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -1 +0,0 @@
|
||||
@import url('Night.css') screen and (prefers-color-scheme: dark);
|
||||
@@ -1,298 +0,0 @@
|
||||
body {
|
||||
background-color: black;
|
||||
color: #EBEBEB !important;
|
||||
}
|
||||
|
||||
a:not(.btn) {
|
||||
color: #63a7e1;
|
||||
}
|
||||
|
||||
.btn {
|
||||
box-shadow: 1px 1px 1px rgba(255, 255, 255, .1) !important;
|
||||
}
|
||||
|
||||
.btn:not(.btn-danger),
|
||||
.btn-default,
|
||||
input,
|
||||
select,
|
||||
textarea,
|
||||
.advanced-button,
|
||||
.list-group-item {
|
||||
border-color: #252525 !important;
|
||||
}
|
||||
|
||||
#addFeed,
|
||||
#addFeedContent,
|
||||
.section {
|
||||
border-bottom: 1px solid #555555;
|
||||
}
|
||||
|
||||
.col2 p,
|
||||
.col2-cats {
|
||||
color: #AAA;
|
||||
}
|
||||
|
||||
.col2 h3 {
|
||||
background: none repeat scroll 0 0 #555555;
|
||||
}
|
||||
|
||||
.catTable,
|
||||
.dropdown-menu,
|
||||
.dropdown-menu .divider,
|
||||
.even,
|
||||
.Key tr:nth-child(odd),
|
||||
.language:hover,
|
||||
.navbar-default .navbar-nav>.open>a,
|
||||
.navbar-default .navbar-nav>.open>a:focus,
|
||||
.navbar-default .navbar-nav>.open>a:hover,
|
||||
.navbar-default .navbar-nav>li>a.active,
|
||||
.navbar-default .navbar-nav>li>a:hover,
|
||||
.navbar-default .navbar-nav>li>a:focus,
|
||||
.navbar-logo:hover,
|
||||
.quoteBlock,
|
||||
.server-disabled,
|
||||
#serverResponse,
|
||||
.table>tbody>tr:nth-child(odd),
|
||||
.table-striped>tbody>tr:nth-child(odd),
|
||||
ul.tabs li.active a,
|
||||
select[disabled],
|
||||
select:hover {
|
||||
background-color: #444444 !important;
|
||||
color: #EBEBEB !important;
|
||||
}
|
||||
|
||||
.failed {
|
||||
color: #ff3333 !important;
|
||||
}
|
||||
|
||||
#rightGreyText,
|
||||
small {
|
||||
color: #c7c7c7 !important;
|
||||
}
|
||||
|
||||
.Categories form.sorting-row:nth-child(2n-1) tr,
|
||||
.advanced-button,
|
||||
.advanced-buttonSeperator,
|
||||
.alt,
|
||||
.infoTableSeperator.alt,
|
||||
.btn:not(.btn-danger),
|
||||
.btn-default.disabled:active,
|
||||
.btn-default.disabled:focus,
|
||||
.btn-default.disabled:hover,
|
||||
a.btn.btn-default,
|
||||
select.form-control,
|
||||
.form-control[disabled],
|
||||
.input-group-addon,
|
||||
#inner,
|
||||
.navbar-default,
|
||||
.search-box input,
|
||||
.select,
|
||||
.table-striped>tbody>tr:nth-child(even),
|
||||
.table>tbody>tr:nth-child(even),
|
||||
.tab-pane tr:nth-child(odd),
|
||||
textarea,
|
||||
ul.tabs a.active,
|
||||
a.list-group-item,
|
||||
.dropdown-menu>li>a,
|
||||
input[type="text"],
|
||||
input[type="email"],
|
||||
input[type="url"],
|
||||
input[type="date"],
|
||||
input[type="number"],
|
||||
input[type="password"],
|
||||
input[disabled],
|
||||
textarea,
|
||||
select {
|
||||
background-color: #555555;
|
||||
color: #EBEBEB;
|
||||
}
|
||||
|
||||
.btn:hover:not(.btn-danger),
|
||||
.btn-default:hover,
|
||||
.tab-content .catTable tr:hover td,
|
||||
input:hover,
|
||||
textarea:hover,
|
||||
a.list-group-item:hover,
|
||||
select:hover,
|
||||
textarea:hover,
|
||||
input[type="date"]:hover,
|
||||
input[type="datetime"]:hover,
|
||||
input[type="datetime-local"]:hover,
|
||||
input[type="email"]:hover,
|
||||
input[type="month"]:hover,
|
||||
input[type="number"]:hover,
|
||||
input[type="password"]:hover,
|
||||
input[type="search"]:hover,
|
||||
input[type="tel"]:hover,
|
||||
input[type="text"]:hover,
|
||||
input[type="time"]:hover,
|
||||
input[type="url"]:hover,
|
||||
input[type="week"]:hover,
|
||||
textarea:focus,
|
||||
select:focus,
|
||||
input[type="date"]:focus,
|
||||
input[type="datetime"]:focus,
|
||||
input[type="datetime-local"]:focus,
|
||||
input[type="email"]:focus,
|
||||
input[type="month"]:focus,
|
||||
input[type="number"]:focus,
|
||||
input[type="password"]:focus,
|
||||
input[type="search"]:focus,
|
||||
input[type="tel"]:focus,
|
||||
input[type="text"]:focus,
|
||||
input[type="time"]:focus,
|
||||
input[type="url"]:focus,
|
||||
input[type="week"]:focus {
|
||||
background-color: #666;
|
||||
color: #EBEBEB;
|
||||
}
|
||||
|
||||
.btn-default:focus,
|
||||
.form-control:focus,
|
||||
input:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
border-color: #707070 !important;
|
||||
outline: initial !important;
|
||||
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
background-color: #262626 !important;
|
||||
}
|
||||
|
||||
.Key tr {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.table>tbody>tr>td,
|
||||
.table>tbody>tr>th,
|
||||
.infoTableSeperator,
|
||||
.modal-footer,
|
||||
.data-row {
|
||||
border-top: 1px solid #555555;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-top: 1px solid #555555;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
border-color: #7b2b28;
|
||||
}
|
||||
|
||||
.tab-content .catTable tbody,
|
||||
ul.tabs a,
|
||||
.colmask,
|
||||
#subscriptions,
|
||||
.RSS form[action="add_rss_feed"] tr:nth-child(even),
|
||||
.Config .table {
|
||||
border: 1px solid #555555;
|
||||
}
|
||||
|
||||
.Categories form:first-of-type tr:last-of-type,
|
||||
.default,
|
||||
.dropdown-menu>li>a:focus,
|
||||
.dropdown-menu>li>a:hover {
|
||||
background-color: #696969;
|
||||
}
|
||||
|
||||
.activeRSS,
|
||||
.activeRSS a,
|
||||
.activeRSS a:visited,
|
||||
.btn-default,
|
||||
.checkbox label,
|
||||
.feed-row td,
|
||||
.help-block,
|
||||
#content,
|
||||
.navbar-default .navbar-nav>li>a,
|
||||
.navbar-default .navbar-nav>li>a>.glyphicon,
|
||||
.path,
|
||||
.Servers .ct-label,
|
||||
.time,
|
||||
.main-restarting.in,
|
||||
#search-dropdown .dropdown-header,
|
||||
ul.tabs a,
|
||||
a.wizard-advanced-settings,
|
||||
.quoteBlock a,
|
||||
a.main-helplink,
|
||||
col2 h3 a,
|
||||
.text-center a,
|
||||
.text-center a:hover {
|
||||
color: #EBEBEB;
|
||||
}
|
||||
|
||||
.container,
|
||||
#content {
|
||||
background-color: unset !important;
|
||||
}
|
||||
|
||||
#content>div.colmask>div:nth-child(3) {
|
||||
border-bottom: 1px solid #555555 !important;
|
||||
}
|
||||
|
||||
.Servers .ct-series-a .ct-line,
|
||||
.Servers .ct-series-a .ct-point {
|
||||
stroke: #EBEBEB;
|
||||
}
|
||||
|
||||
#inner,
|
||||
.colmask {
|
||||
background-color: #303030;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
background-color: #3C3C3C;
|
||||
}
|
||||
|
||||
.modal-content,
|
||||
.modal-body,
|
||||
.modal-footer {
|
||||
background-color: #727272;
|
||||
}
|
||||
|
||||
#modal_qr .modal-body {
|
||||
background-color: #EBEBEB;
|
||||
}
|
||||
|
||||
.form-signin .btn.btn-default {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.rss-icon-svg {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
.rss-symbol {
|
||||
fill: #555555;
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: #EBEBEB !important;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
background-color: #E4E4E4 !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
/* for login */
|
||||
.tooltip.bottom .tooltip-arrow {
|
||||
border-bottom-color: #E4E4E4 !important;
|
||||
}
|
||||
/* config>general - host-warning */
|
||||
.tooltip.top .tooltip-arrow {
|
||||
border-top-color: #E4E4E4 !important;
|
||||
}
|
||||
|
||||
.tooltip.left .tooltip-arrow {
|
||||
border-left-color: #E4E4E4 !important;
|
||||
}
|
||||
|
||||
.tooltip.right .tooltip-arrow {
|
||||
border-right-color: #E4E4E4 !important;
|
||||
}
|
||||
|
||||
.Special .glyphicon-asterisk {
|
||||
color: #E4E4E4 !important;
|
||||
}
|
||||
@@ -1,18 +1,32 @@
|
||||
:root {
|
||||
/* Follow the OS by default (Auto); forced by data-color-scheme below */
|
||||
color-scheme: light dark;
|
||||
|
||||
/* Color palette — light-dark(light value, dark value) */
|
||||
--clr-page-bg: light-dark(#E4E4E4, black);
|
||||
--clr-surface: light-dark(#FFFFFF, #303030);
|
||||
--clr-input-bg: light-dark(#FFFFFF, #555555);
|
||||
--clr-border: light-dark(rgba(0, 0, 0, 0.15), #555555);
|
||||
--clr-text: light-dark(#000000, #EBEBEB);
|
||||
--clr-text-muted: light-dark(#636363, #c7c7c7);
|
||||
--radius-lg: 8px;
|
||||
--clr-toggle-active: #f9ca33;
|
||||
--clr-toggle-inactive: light-dark(#aaaaaa, #666666);
|
||||
}
|
||||
|
||||
/* The server renders the configured scheme into this attribute; empty/unknown = Auto */
|
||||
html[data-color-scheme="light" i] {
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
html[data-color-scheme="night" i] {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow-y: scroll;
|
||||
background-color: #E4E4E4;
|
||||
}
|
||||
|
||||
* {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.btn,
|
||||
.btn:hover,
|
||||
.btn:active,
|
||||
.btn:focus {
|
||||
box-shadow: 1px 1px 1px rgba(0,0,0,.1) !important;
|
||||
background-color: white !important;
|
||||
background-color: var(--clr-page-bg);
|
||||
color: var(--clr-text);
|
||||
}
|
||||
|
||||
.logo-header {
|
||||
@@ -25,38 +39,55 @@ body {
|
||||
}
|
||||
|
||||
.account-wall {
|
||||
width: 300px;
|
||||
width: 400px;
|
||||
position: absolute;
|
||||
top: 30%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -30%);
|
||||
transform: translate(-50%, -30%);
|
||||
background-color: var(--clr-surface);
|
||||
border: 1px solid var(--clr-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 25px 40px 15px;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.text-center a {
|
||||
position: absolute;
|
||||
right: 13px;
|
||||
top: 12px;
|
||||
color: #636363;
|
||||
color: var(--clr-text-muted);
|
||||
font-size: 1.2em
|
||||
}
|
||||
|
||||
.text-center a:hover {
|
||||
color: black;
|
||||
color: var(--clr-text);
|
||||
}
|
||||
|
||||
.form-signin .alert {
|
||||
margin: 5px 0px;
|
||||
}
|
||||
|
||||
|
||||
.form-signin input {
|
||||
margin-top: 5px
|
||||
}
|
||||
|
||||
.form-signin input,
|
||||
.form-signin .btn {
|
||||
background-color: var(--clr-input-bg);
|
||||
color: var(--clr-text);
|
||||
border-color: light-dark(#ccc, #252525);
|
||||
}
|
||||
|
||||
.form-signin .btn {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
font-weight: bold;
|
||||
box-shadow: 1px 1px 1px light-dark(transparent, rgba(255, 255, 255, .1));
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: var(--clr-text) !important;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.btn .glyphicon {
|
||||
@@ -66,12 +97,109 @@ body {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-top: 2px;
|
||||
/* Toggle switch — text on the left, switch on the right */
|
||||
label {
|
||||
margin-top: 10px;
|
||||
color: var(--clr-text-muted);
|
||||
}
|
||||
|
||||
label {
|
||||
color: #636363;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
position: relative;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
width: 36px;
|
||||
height: 20px;
|
||||
background-color: var(--clr-toggle-inactive);
|
||||
background-image:
|
||||
radial-gradient(circle at 10px 10px, #ffffff 6.5px, rgba(255,255,255,0) 7px),
|
||||
radial-gradient(circle at 11px 11px, rgba(0,0,0,0.30) 6.5px, transparent 9.5px);
|
||||
background-size: 20px 20px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0px center;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, background-position 0.15s;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked {
|
||||
background-color: var(--clr-toggle-active);
|
||||
background-position: 16px center;
|
||||
background-image:
|
||||
radial-gradient(circle at 10px 10px, #ffffff 6.5px, rgba(255,255,255,0) 7px),
|
||||
radial-gradient(circle at 10.5px 10.5px, rgba(0,0,0,0.30) 6.5px, transparent 9.5px);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:focus-visible {
|
||||
outline: 2px solid var(--clr-toggle-active);
|
||||
outline-offset: 2px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/***
|
||||
Dark-mode structural rules
|
||||
Colors live in the light-dark() tokens above; these are the rules that cannot
|
||||
be expressed as a color value. The two blocks below MUST stay identical:
|
||||
the first applies when Night is forced, the second when the OS is dark and Light is not forced.
|
||||
***/
|
||||
html[data-color-scheme="night" i] {
|
||||
/* Focus / active border */
|
||||
.form-signin input:focus,
|
||||
.form-signin .btn:focus {
|
||||
border-color: #707070 !important;
|
||||
outline: initial !important;
|
||||
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
|
||||
}
|
||||
|
||||
.text-center a,
|
||||
.text-center a:hover {
|
||||
color: var(--clr-text);
|
||||
}
|
||||
|
||||
/* Tooltip — inverted (light tooltip on dark page) */
|
||||
.tooltip-inner {
|
||||
background-color: #E4E4E4 !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
.tooltip.bottom .tooltip-arrow {
|
||||
border-bottom-color: #E4E4E4 !important;
|
||||
}
|
||||
|
||||
.tooltip.top .tooltip-arrow {
|
||||
border-top-color: #E4E4E4 !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html:not([data-color-scheme="light" i]) {
|
||||
/* Focus / active border */
|
||||
.form-signin input:focus,
|
||||
.form-signin .btn:focus {
|
||||
border-color: #707070 !important;
|
||||
outline: initial !important;
|
||||
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
|
||||
}
|
||||
|
||||
.text-center a,
|
||||
.text-center a:hover {
|
||||
color: var(--clr-text);
|
||||
}
|
||||
|
||||
/* Tooltip — inverted (light tooltip on dark page) */
|
||||
.tooltip-inner {
|
||||
background-color: #E4E4E4 !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
.tooltip.bottom .tooltip-arrow {
|
||||
border-bottom-color: #E4E4E4 !important;
|
||||
}
|
||||
|
||||
.tooltip.top .tooltip-arrow {
|
||||
border-top-color: #E4E4E4 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because one or more lines are too long.
File diff suppressed because one or more lines are too long.
File diff suppressed because one or more lines are too long.
@@ -243,6 +243,11 @@ $.fn.extractFormDataTo = function(target) {
|
||||
*
|
||||
* (c) 2015 SABnzbd Team, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
$.ajaxSetup({
|
||||
headers: { "X-SABnzbd-CSRF": csrfToken }
|
||||
});
|
||||
|
||||
function config_success() {
|
||||
$('.saveButton[disabled=disabled]').each(function () {
|
||||
$(this).removeAttr("disabled").html('<span class="glyphicon glyphicon-ok"></span> '+configTranslate.saveChanges);
|
||||
@@ -291,7 +296,7 @@ function do_restart() {
|
||||
$('.main-restarting .restarting-url').text(urlTotal)
|
||||
|
||||
// Initiate restart
|
||||
$.ajax({ url: '../../api?mode=restart&apikey=' + sabSession,
|
||||
$.ajax({ url: rootURL + 'api?mode=restart', type: 'POST',
|
||||
complete: function() {
|
||||
// Keep counter of failures
|
||||
var loopCounter = 0;
|
||||
@@ -340,14 +345,6 @@ function removeObfuscation() {
|
||||
return true
|
||||
}
|
||||
|
||||
// Add coloring to rows (shorthand function)
|
||||
function addRowColor() {
|
||||
// Have to do it seperate for each section
|
||||
$('.section').each(function(i, elmn) {
|
||||
$(elmn).find('.field-pair:visible').removeClass('even').filter(':even').addClass('even')
|
||||
})
|
||||
}
|
||||
|
||||
// Set default functions for the autocomplete everywhere
|
||||
jQuery.extend(jQuery.fn.typeahead.defaults, {
|
||||
source: function (query, process) {
|
||||
@@ -379,6 +376,8 @@ jQuery.extend(jQuery.fn.typeahead.defaults, {
|
||||
})
|
||||
|
||||
$(document).ready(function () {
|
||||
$('form').append('<input type="hidden" name="csrf_token" value="' + csrfToken + '">');
|
||||
|
||||
/**
|
||||
Restart function
|
||||
**/
|
||||
@@ -411,7 +410,7 @@ $(document).ready(function () {
|
||||
$(this).attr("disabled", "disabled").removeClass('btn-danger').html('<span class="glyphicon glyphicon-transfer"></span> ' + configTranslate.saving);
|
||||
});
|
||||
},
|
||||
success: function (json) {
|
||||
success: function (json, statusText, xhr, form) {
|
||||
if (json.error) {
|
||||
$('#config_err_msg').text(json.error);
|
||||
alert(json.error)
|
||||
@@ -425,6 +424,12 @@ $(document).ready(function () {
|
||||
$('#config_err_msg').text(" ");
|
||||
setTimeout(config_success, 1000);
|
||||
}
|
||||
} else if(form && form.is('[data-reload-on-save]')) {
|
||||
// Values changed that are rendered by the server, so reload the page
|
||||
$('#config_err_msg').text(" ");
|
||||
formWasSubmitted = true;
|
||||
formHasChanged = false;
|
||||
location.reload();
|
||||
} else {
|
||||
$('#config_err_msg').text(" ");
|
||||
setTimeout(config_success, 1000);
|
||||
@@ -482,16 +487,15 @@ $(document).ready(function () {
|
||||
$('.advanced-button').on('change', function(event){
|
||||
localStorage.setItem('advanced-settings', !$('.advanced-settings').is(':visible'))
|
||||
$('.advanced-settings').toggle()
|
||||
addRowColor()
|
||||
})
|
||||
if(localStorage.getItem('advanced-settings') === 'true') {
|
||||
$('.advanced-settings').show()
|
||||
$('#advanced-settings-button').prop('checked', true)
|
||||
addRowColor()
|
||||
}
|
||||
addRowColor()
|
||||
|
||||
// Add tooltips
|
||||
// Render tooltips in the body, otherwise they get clipped by sections with overflow: hidden
|
||||
jQuery.fn.tooltip.Constructor.DEFAULTS.container = 'body'
|
||||
jQuery('[title]').tooltip()
|
||||
});
|
||||
|
||||
@@ -512,16 +516,56 @@ var pagesContainer = new Array(arrPages.length);
|
||||
// Add trigger to focus on the field and load the results
|
||||
$(document).ready(function() {
|
||||
$('#search-menu').on('shown.bs.dropdown', function(event) {
|
||||
setConfigSearchExpanded(true)
|
||||
// Focus so easy typing
|
||||
$('#search-box').focus()
|
||||
// Load things to search if we haven't yet
|
||||
if(!pagesContainer[0]) {
|
||||
$.each(arrPages, function(index, page) {
|
||||
$.get(rootURL + 'config/' + page + '/', function(data) {
|
||||
$.get(rootURL + 'config/' + page, function(data) {
|
||||
pagesContainer[index] = $(data).find('label')
|
||||
});
|
||||
});
|
||||
}
|
||||
}).on('hidden.bs.dropdown', function(event) {
|
||||
setConfigSearchExpanded(false)
|
||||
});
|
||||
|
||||
$('#search-box').on('keydown', function(event) {
|
||||
var key = event.key || event.which;
|
||||
var isArrowDown = key === 'ArrowDown' || key === 40;
|
||||
var isArrowUp = key === 'ArrowUp' || key === 38;
|
||||
var isEscape = key === 'Escape' || key === 'Esc' || key === 27;
|
||||
|
||||
if(isArrowDown || isArrowUp) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
focusConfigSearchResult(isArrowDown ? 1 : -1)
|
||||
} else if(isEscape) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
closeConfigSearch()
|
||||
}
|
||||
});
|
||||
|
||||
$('#search-dropdown').on('keydown', 'a.config-search-result', function(event) {
|
||||
var key = event.key || event.which;
|
||||
var isArrowDown = key === 'ArrowDown' || key === 40;
|
||||
var isArrowUp = key === 'ArrowUp' || key === 38;
|
||||
var isEscape = key === 'Escape' || key === 'Esc' || key === 27;
|
||||
|
||||
if(isArrowDown || isArrowUp) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
focusConfigSearchResult(isArrowDown ? 1 : -1)
|
||||
} else if(isEscape) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
closeConfigSearch()
|
||||
}
|
||||
}).on('mouseenter focus', 'a.config-search-result', function() {
|
||||
getConfigSearchResults().parent().removeClass('active')
|
||||
$(this).parent().addClass('active')
|
||||
});
|
||||
|
||||
// For the scrolling
|
||||
@@ -547,11 +591,46 @@ $(document).ready(function() {
|
||||
|
||||
// Don't go too fast
|
||||
var searchTimeout
|
||||
|
||||
function getConfigSearchResults() {
|
||||
return $('#search-dropdown').find('a.config-search-result')
|
||||
}
|
||||
|
||||
function setConfigSearchExpanded(expanded) {
|
||||
$('#search-menu > a[data-toggle="dropdown"]').attr('aria-expanded', expanded ? 'true' : 'false')
|
||||
}
|
||||
|
||||
function closeConfigSearch() {
|
||||
$('#search-menu').removeClass('open')
|
||||
setConfigSearchExpanded(false)
|
||||
$('#search-box').focus()
|
||||
}
|
||||
|
||||
function focusConfigSearchResult(offset) {
|
||||
var $results = getConfigSearchResults()
|
||||
var activeIndex = $results.index(document.activeElement)
|
||||
var nextIndex
|
||||
|
||||
if(!$results.length) return
|
||||
|
||||
if(activeIndex < 0) {
|
||||
nextIndex = offset > 0 ? 0 : $results.length - 1
|
||||
} else {
|
||||
nextIndex = activeIndex + offset
|
||||
if(nextIndex >= $results.length) nextIndex = 0
|
||||
if(nextIndex < 0) nextIndex = $results.length - 1
|
||||
}
|
||||
|
||||
getConfigSearchResults().parent().removeClass('active')
|
||||
$results.eq(nextIndex).parent().addClass('active')
|
||||
$results.eq(nextIndex).focus()
|
||||
}
|
||||
|
||||
function doConfigSearch(value) {
|
||||
// Cancel previous
|
||||
clearTimeout(searchTimeout)
|
||||
// Build new search
|
||||
var searchTerm = $(value).val().replace('"', '\"')
|
||||
var searchTerm = $.trim($(value).val())
|
||||
var searchOutput = $('#search-dropdown')
|
||||
|
||||
// Build new search
|
||||
@@ -562,14 +641,24 @@ function doConfigSearch(value) {
|
||||
if (searchTerm.length < 2) return
|
||||
// Find some results!
|
||||
$.each(pagesContainer, function(page_index, results) {
|
||||
if(!results) return
|
||||
// Get the matches
|
||||
var subResults = results.filter(':contains("'+searchTerm+'")')
|
||||
var subResults = results.filter(function() {
|
||||
return $(this).text().toUpperCase().indexOf(searchTerm.toUpperCase()) >= 0
|
||||
})
|
||||
if(subResults.length > 0) {
|
||||
// Add the section
|
||||
searchOutput.append('<li class="divider"></li>')
|
||||
searchOutput.append('<li class="dropdown-header">'+configTranslate.searchPages[page_index]+'</li>')
|
||||
searchOutput.append($('<li class="divider"></li>'))
|
||||
searchOutput.append($('<li class="dropdown-header"></li>').text(configTranslate.searchPages[page_index]))
|
||||
$.each(subResults, function(index, result) {
|
||||
searchOutput.append('<li><a href="'+rootURL + 'config/' + arrPages[page_index] + '/#' + $(result).attr('for') +'">'+$(result).text()+'</a></li>')
|
||||
var resultUrl = rootURL + 'config/' + arrPages[page_index] + '#' + $(result).attr('for')
|
||||
searchOutput.append(
|
||||
$('<li></li>').append(
|
||||
$('<a class="config-search-result"></a>')
|
||||
.attr('href', resultUrl)
|
||||
.text($(result).text())
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<div class="history" id="history-tab">
|
||||
<div class="history-header">
|
||||
<h2>$T('menu-history') <small data-bind="visible: history.showArchive()">($T('archive'))</small></h2>
|
||||
<a href="#" data-bind="click: history.showMultiEdit, visible: hasHistory()">
|
||||
<a href="#" aria-label="$T('Glitter-multiOperations')" data-bind="click: history.showMultiEdit, visible: hasHistory()">
|
||||
<span class="glyphicon glyphicon-tasks" data-tooltip="true" data-placement="left" title="$T('Glitter-multiOperations')"></span>
|
||||
</a>
|
||||
</div>
|
||||
<table class="table table-hover history-table paginated">
|
||||
<table class="table table-hover history-table paginated" aria-label="$T('menu-history')">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 25px;"></th>
|
||||
<th></th>
|
||||
<th class="table-status-header" data-bind="css: { 'table-header-status-smaller' : extraHistoryColumns().length }"></th>
|
||||
<th scope="col" style="width: 25px;"><span class="sr-only">$T('Glitter-result')</span></th>
|
||||
<th scope="col"><span class="sr-only">$T('name')</span></th>
|
||||
<th class="table-status-header" scope="col" data-bind="css: { 'table-header-status-smaller' : extraHistoryColumns().length || displayCompact() }"><span class="sr-only">$T('status')</span></th>
|
||||
<!-- ko foreach: extraHistoryColumns -->
|
||||
<th class="table-header-extra"></th>
|
||||
<th class="table-header-extra" scope="col"><span class="sr-only" data-bind="text: glitterTranslate.column[\$data]"></span></th>
|
||||
<!-- /ko -->
|
||||
<th style="width: 130px;"></th>
|
||||
<th style="width: 60px;"></th>
|
||||
<th scope="col" style="width: 130px;"><span class="sr-only">$T('post-Completed')</span></th>
|
||||
<th scope="col" style="width: 60px;"><span class="sr-only">$T('Glitter-actions')</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!-- ko if: !hasHistory() -->
|
||||
@@ -30,10 +30,10 @@
|
||||
<tbody data-bind="foreach: history.historyItems, visible: hasHistory()" style="display: none;">
|
||||
<tr class="history-item" data-bind="css: {'history-failed-download':failed()}">
|
||||
<td>
|
||||
<div data-bind="visible: processingWaiting()">
|
||||
<span class="glyphicon glyphicon-time"></span>
|
||||
<div role="img" aria-label="$T('post-Queued')" data-bind="visible: processingWaiting()">
|
||||
<span class="glyphicon glyphicon-time" aria-hidden="true"></span>
|
||||
</div>
|
||||
<div data-bind="visible: processingDownload()">
|
||||
<div role="img" aria-label="$T('stage-download')" data-bind="visible: processingDownload()">
|
||||
<div class="processing-download">
|
||||
<div class="loader-bar-one"></div>
|
||||
<div class="loader-bar-two"></div>
|
||||
@@ -41,17 +41,17 @@
|
||||
<div class="loader-bar-four"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-bind="visible: (!failed() && !processingDownload() && !processingWaiting())">
|
||||
<span class="glyphicon glyphicon-ok"></span>
|
||||
<div role="img" aria-label="$T('post-Completed')" data-bind="visible: (!failed() && !processingDownload() && !processingWaiting())">
|
||||
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
|
||||
</div>
|
||||
<div data-bind="visible: failed() && canRetry()">
|
||||
<a class="retry-button" href="#" data-bind="click: retry">
|
||||
<span class="glyphicon glyphicon-exclamation-sign"></span>
|
||||
<a class="retry-button" href="#" aria-label="$T('button-retry')" data-bind="click: retry">
|
||||
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div data-bind="visible: failed() && !canRetry()">
|
||||
<span class="retry-button-inactive">
|
||||
<span class="glyphicon glyphicon-exclamation-sign"></span>
|
||||
<span class="retry-button-inactive" role="img" aria-label="$T('post-Failed')">
|
||||
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
@@ -70,10 +70,10 @@
|
||||
<td class="history-completedon row-wrap-text" data-bind="text: completedOn(), attr: { 'data-timestamp': completed }" onclick="showDetails(this)"></td>
|
||||
<td class="delete">
|
||||
<label data-bind="visible: parent.isMultiEditing()">
|
||||
<input type="checkbox" name="multiedit" title="$T('Glitter-multiSelect')" data-bind="click: parent.addMultiEdit, attr: { 'id': 'multiedit_' + id } " />
|
||||
<input type="checkbox" name="multiedit" title="$T('Glitter-multiSelect')" aria-label="$T('Glitter-selectJob')" data-bind="click: parent.addMultiEdit, attr: { 'id': 'multiedit_' + id } " />
|
||||
</label>
|
||||
<div class="dropdown" data-bind="visible: !parent.isMultiEditing()">
|
||||
<a href="#" data-toggle="dropdown" data-bind="click: updateAllHistoryInfo">
|
||||
<a href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="$T('nzoDetails')" data-bind="click: updateAllHistoryInfo">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<!-- ko if: hasDropdown() -->
|
||||
@@ -95,7 +95,6 @@
|
||||
<div class="col-sm-2">$T('status')</div>
|
||||
<div class="col-sm-10">
|
||||
<span data-bind="text: glitterTranslate.status[historyStatus.status()] ? glitterTranslate.status[historyStatus.status()] : statusText()"></span>
|
||||
<a href="#" class="mark-completed-link" data-bind="visible: failed(), click: markAsCompleted" title="$T('button-mark-completed')"><span class="glyphicon glyphicon-ok"></span> $T('post-Completed')</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
@@ -120,11 +119,14 @@
|
||||
<div class="col-sm-10 history-status-modallink" data-bind="longText: actions, longTextType: name()"></div>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<div class="col-sm-12 text-right" data-bind="visible: failed()">
|
||||
<a href="#" class="btn btn-default mark-completed-btn" data-bind="click: markAsCompleted"><span class="glyphicon glyphicon-ok"></span> $T('button-mark-completed')</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
</div>
|
||||
<a href="#" data-bind="click: parent.triggerRemoveDownload">
|
||||
<a href="#" data-bind="click: parent.triggerRemoveDownload, attr: { 'aria-label': processingDownload() == 2 ? '$T('abort')' : '$T('nzo-delete')' }">
|
||||
<span class="hover-button glyphicon glyphicon-trash" data-bind="css: { 'glyphicon-stop' : processingDownload() == 2, disabled : processingDownload() == 1 }, attr: { title: processingDownload() == 2 ? '$T('abort')' : '$T('nzo-delete')' }"></span>
|
||||
</a>
|
||||
</td>
|
||||
@@ -132,16 +134,23 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="history-footer">
|
||||
|
||||
<div class="input-group search-box">
|
||||
<input type="text" class="form-control" placeholder="$T('Glitter-search')" required data-bind="textInput: history.searchTerm, event: { keydown: history.clearSearchTerm }" />
|
||||
<a data-bind="event: { mousedown: history.clearSearchTerm }">
|
||||
<input type="text" class="form-control" placeholder="$T('Glitter-search')" aria-label="$T('Glitter-search')" required data-bind="textInput: history.searchTerm, event: { keydown: history.clearSearchTerm }" />
|
||||
<a href="#" data-tooltip="true" data-html="true" data-placement="right" title="$T('Glitter-searchExplain')" data-bind="click: history.clearSearchTerm, attr: { 'aria-label': history.searchTerm() ? '$T('Glitter-clearSearch')' : '$T('Glitter-search')' }">
|
||||
<span class="glyphicon" data-bind="css: { 'glyphicon-search' : !history.searchTerm(), 'glyphicon-remove' : history.searchTerm() }"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="pagination" data-bind="foreach: history.pagination.allpages(), visible: history.pagination.hasPagination" style="display: none;">
|
||||
<li data-bind="css: { active: isCurrent, disabled: isDots }, click: onclick">
|
||||
<span data-bind="text: page"></span>
|
||||
<li data-bind="css: { active: isCurrent, disabled: isDots }">
|
||||
<!-- ko ifnot: isDots -->
|
||||
<a href="#" data-bind="text: page, click: onclick, attr: { 'aria-current': isCurrent ? 'page' : null }"></a>
|
||||
<!-- /ko -->
|
||||
<!-- ko if: isDots -->
|
||||
<span aria-hidden="true" data-bind="text: page"></span>
|
||||
<!-- /ko -->
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -172,4 +181,6 @@
|
||||
<span data-bind="text: history.downloadedMonth"></span>B $T('Glitter-thisMonth')
|
||||
<span data-bind="text: history.downloadedTotal"></span>B $T('Glitter-total')
|
||||
</div>
|
||||
|
||||
</div><!-- /.history-footer -->
|
||||
</div>
|
||||
@@ -1,19 +1,19 @@
|
||||
<nav class="navbar navbar-inverse main-navbar">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse" aria-label="$T('Glitter-toggleNavigation')" aria-controls="navbar-collapse" aria-expanded="false">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-logo" href="./">
|
||||
<a class="navbar-logo" href="$url()" aria-label="SABnzbd $T('menu-queue')">
|
||||
#include $webdir + "/../../Config/templates/staticcfg/images/logo-small.svg"#
|
||||
</a>
|
||||
<div class="btn-group">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default navbar-btn" data-bind="click: pauseToggle, attr: { 'title': downloadsPaused() ? '$T('link-resume')' : '$T('link-pause')' }">
|
||||
<button type="button" class="btn btn-default navbar-btn" data-bind="click: pauseToggle, attr: { 'title': downloadsPaused() ? '$T('link-resume')' : '$T('link-pause')', 'aria-label': downloadsPaused() ? '$T('link-resume')' : '$T('link-pause')' }">
|
||||
<span class="glyphicon" data-bind="css: { 'glyphicon-play' : downloadsPaused(), 'glyphicon-pause' : !downloadsPaused() }"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default navbar-btn dropdown-toggle" data-toggle="dropdown">
|
||||
<button type="button" class="btn btn-default navbar-btn dropdown-toggle" data-toggle="dropdown" aria-label="$T('pauseFor')" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
@@ -26,7 +26,7 @@
|
||||
<li class="divider"></li>
|
||||
<li><a href="#" data-bind="click: openCustomPauseTime">$T('Glitter-custom')</a></li>
|
||||
</ul>
|
||||
<span class="btn btn-default navbar-btn navbar-timeleft" data-bind="text: timeLeft" data-toggle="dropdown">0:00</span>
|
||||
<span class="btn btn-default navbar-btn navbar-timeleft" data-bind="text: timeLeft" data-toggle="dropdown">0:00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -37,18 +37,18 @@
|
||||
<li class="speedlimit-dropdown dropdown">
|
||||
<div class="btn-group">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default navbar-btn navbar-speed" data-toggle="dropdown">
|
||||
<button type="button" class="btn btn-default navbar-btn navbar-speed" data-toggle="dropdown" aria-haspopup="true">
|
||||
<span data-bind="text: speedText">0 KB/s</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default navbar-btn dropdown-toggle" data-toggle="dropdown" onclick="keepOpen(this)">
|
||||
<button type="button" class="btn btn-default navbar-btn dropdown-toggle" data-toggle="dropdown" onclick="keepOpen(this)" aria-hidden="true" tabindex="-1">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<a href="#" class="max-speed-input-clear hover-button" data-bind="click: clearSpeedLimit, visible:(speedLimit() < 100 && speedLimit() > 0)" style="display: none;">
|
||||
<a href="#" class="max-speed-input-clear hover-button" aria-label="$T('button-clear')" 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">
|
||||
<div data-bind="visible: !bandwithLimit()">
|
||||
<a href="./config/general/#bandwidth_max_value">
|
||||
<a href="$url('config/general#bandwidth_max_value')">
|
||||
<span class="glyphicon glyphicon-cog"></span> $T('Glitter-setMaxLinespeed')
|
||||
</a>
|
||||
</div>
|
||||
@@ -61,14 +61,14 @@
|
||||
</div>
|
||||
</li>
|
||||
<li data-tooltip="true" data-placement="bottom" title="$T('Glitter-addNZB')">
|
||||
<a href="#modal-add-nzb" data-toggle="modal"><span class="glyphicon glyphicon-plus-sign"></span></a>
|
||||
<a href="#modal-add-nzb" data-toggle="modal" aria-label="$T('Glitter-addNZB')"><span class="glyphicon glyphicon-plus-sign"></span></a>
|
||||
</li>
|
||||
<li data-tooltip="true" data-placement="bottom" title="$T('Glitter-statusInterfaceOptions')" data-bind="click: loadStatusInfo">
|
||||
<a href="#modal-options" data-toggle="modal"><span class="glyphicon glyphicon-wrench"></span></a>
|
||||
<a href="#modal-options" data-toggle="modal" aria-label="$T('Glitter-statusInterfaceOptions')"><span class="glyphicon glyphicon-wrench"></span></a>
|
||||
</li>
|
||||
<!--#if $have_rss_defined#-->
|
||||
<li data-tooltip="true" data-placement="bottom" title="$T('cmenu-rss')">
|
||||
<a href="./config/rss/">
|
||||
<a href="$url('config/rss')" aria-label="$T('cmenu-rss')">
|
||||
<svg class="rss-icon-svg" viewBox="0 0 8 8">
|
||||
<rect class="rss-button" width="8" height="8" />
|
||||
<circle class="rss-symbol" cx="2" cy="6" r="1" />
|
||||
@@ -79,10 +79,10 @@
|
||||
</li>
|
||||
<!--#end if#-->
|
||||
<li data-tooltip="true" data-placement="bottom" title="SABnzbd $T('menu-config')">
|
||||
<a href="./config/"><span class="glyphicon glyphicon-cog"></span></a>
|
||||
<a href="$url('config')" aria-label="SABnzbd $T('menu-config')"><span class="glyphicon glyphicon-cog"></span></a>
|
||||
</li>
|
||||
<li class="dropdown main-menu-link" data-bind="css: { 'active-on-queue-finish-menu': finishaction()}">
|
||||
<a href="#" data-toggle="dropdown" onclick="keepOpen(this)">
|
||||
<a href="#" data-toggle="dropdown" onclick="keepOpen(this)" aria-label="$T('Glitter-mainMenu')" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@@ -91,18 +91,32 @@
|
||||
<li><a href="#modal-help" data-toggle="modal"><span class="glyphicon glyphicon-question-sign"></span> $T('menu-help')</a></li>
|
||||
<li><a href="https://sabnzbd.org/donate" target="_blank"><span class="glyphicon glyphicon-heart"></span> $T('menu-donate')</a></li>
|
||||
<!--#if $have_logout or $have_quota or $have_rss_defined or $have_watched_dir or $pp_pause_event#--><li class="divider"></li><!--#end if#-->
|
||||
<!--#if $have_logout#--><li><a href="./login/?logout=1"><span class="glyphicon glyphicon-log-out"></span> $T('logout')</a></li><!--#end if#-->
|
||||
<!--#if $have_logout#--><li>
|
||||
<form method="post" action="$url('logout')">
|
||||
<input type="hidden" name="csrf_token" value="$csrf_token" />
|
||||
<button type="submit"><span class="glyphicon glyphicon-log-out"></span> $T('logout')</button>
|
||||
</form>
|
||||
</li><!--#end if#-->
|
||||
<!--#if $have_quota#--><li><a href="#" data-bind="click: doQueueAction" data-mode="reset_quota">$T('link-resetQuota')</a></li><!--#end if#-->
|
||||
<!--#if $have_rss_defined#--><li><a href="#" data-bind="click: doQueueAction" data-mode="rss_now">$T('button-rssNow')</a></li><!--#end if#-->
|
||||
<!--#if $have_watched_dir#--><li><a href="#" data-bind="click: doQueueAction" data-mode="watched_now">$T('sch-scan_folder')</a></li><!--#end if#-->
|
||||
<!--#if $pp_pause_event#--><li><a href="#" data-bind="click: doQueueAction" data-mode="resume_pp">$T('sch-resume_post')</a></li><!--#end if#-->
|
||||
<li class="divider"></li>
|
||||
<li><a href="./shutdown/?apikey=$apikey&pid=$pid" data-bind="click: shutdownSAB">$T('shutdownSab')</a></li>
|
||||
<li><a href="#" data-bind="click: restartSAB">$T('Glitter-restartSab')</a></li>
|
||||
<li>
|
||||
<form method="post" action="$url('shutdown')" data-bind="submit: shutdownSAB">
|
||||
<input type="hidden" name="csrf_token" value="$csrf_token" />
|
||||
<button type="submit">$T('shutdownSab')</button>
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
<form data-bind="submit: restartSAB">
|
||||
<button type="submit">$T('Glitter-restartSab')</button>
|
||||
</form>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li class="dropdown-header"><span class="glyphicon glyphicon-off"></span> $T('Glitter-onFinish'):</li>
|
||||
<li>
|
||||
<select data-bind="value: finishaction, event: { change: setOnQueueFinish }" class="form-control">
|
||||
<select data-bind="value: finishaction, event: { change: setOnQueueFinish }" class="form-control" aria-label="$T('Glitter-onFinish')">
|
||||
<option value=""></option>
|
||||
<option value="shutdown_program">$T('shutdownSab')</option>
|
||||
<!--#if $power_options#-->
|
||||
@@ -116,4 +130,4 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</nav>
|
||||
@@ -1,8 +1,8 @@
|
||||
<div id="queue-messages" class="queue-messages" data-bind="visible: hasMessages() || displayTabbed()" style="display: none;">
|
||||
<table class="table table-hover table-messages">
|
||||
<table class="table table-hover table-messages" aria-label="$T('warnings')">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-messages-header-label"></th>
|
||||
<th class="table-messages-header-label"><span class="sr-only">$T('warnings')</span></th>
|
||||
<th style="width: 30px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -11,7 +11,7 @@
|
||||
<tr>
|
||||
<td class="table-messages-hide"></td>
|
||||
<td data-bind="attr: { 'rowspan': parseInt(nrWarnings())+1 }, click: clearWarnings" class="table-messages-remove">
|
||||
<a href="#" class="hover-button"><span class="glyphicon glyphicon-remove"></span></a>
|
||||
<a href="#" class="hover-button" aria-label="$T('button-clear')"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- ko foreach: allWarnings -->
|
||||
@@ -32,7 +32,7 @@
|
||||
</td>
|
||||
<!-- ko if: \$data.hasOwnProperty("clear") -->
|
||||
<td class="table-messages-remove">
|
||||
<a href="#" data-bind="click: clear" class="hover-button"><span class="glyphicon glyphicon-remove"></span></a>
|
||||
<a href="#" data-bind="click: clear" class="hover-button" aria-label="$T('button-clear')"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></a>
|
||||
</td>
|
||||
<!-- /ko -->
|
||||
</tr>
|
||||
@@ -45,4 +45,4 @@
|
||||
<!-- /ko -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -72,13 +72,13 @@
|
||||
</div>
|
||||
|
||||
<!-- Modals -->
|
||||
<div id="modal-options" class="modal fade" tabindex="-1">
|
||||
<div id="modal-options" class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-options-title">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">×</span></button>
|
||||
<a href="#" data-bind="click: loadStatusInfo, css: { 'rotate-refresh': !hasStatusInfo() }" title="$T('Glitter-interfaceRefresh')"><span class="glyphicon glyphicon-repeat"></span></a>
|
||||
<h4 class="modal-title">$T('Glitter-statusInterfaceOptions')</h4>
|
||||
<h4 class="modal-title" id="modal-options-title">$T('Glitter-statusInterfaceOptions')</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ul class="nav nav-tabs">
|
||||
@@ -197,9 +197,12 @@
|
||||
</div>
|
||||
<div class="row options-function-box">
|
||||
<div class="col-sm-6">
|
||||
<a href="./api?mode=showlog&apikey=$apikey" target="_blank" class="btn btn-default" data-tooltip="true" data-placement="top" title="$T('Glitter-logText')">
|
||||
<span class="glyphicon glyphicon-file"></span> $T('link-showLog')
|
||||
</a>
|
||||
<form method="post" action="$url('log')" target="_blank">
|
||||
<input type="hidden" name="csrf_token" value="$csrf_token" />
|
||||
<button type="submit" class="btn btn-default" data-tooltip="true" data-placement="top" title="$T('Glitter-logText')">
|
||||
<span class="glyphicon glyphicon-file"></span> $T('link-showLog')
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" data-tooltip="true" data-placement="top" title="$T('logging')">
|
||||
@@ -274,7 +277,7 @@
|
||||
</div>
|
||||
|
||||
<!-- ko if: serverconnections().length > 0 -->
|
||||
<table class="table table-hover table-server-connections" data-bind="visible: \$root.showActiveConnections()">
|
||||
<table class="table table-hover table-server-connections" aria-label="$T('connections')" data-bind="visible: \$root.showActiveConnections()">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><strong>$T('article-id')</strong></th>
|
||||
@@ -304,7 +307,7 @@
|
||||
<a href="#" class="hover-button process-all-orphaned" data-bind="click: removeAllOrphaned">$T('Glitter-purgeOrphaned') <span class="glyphicon glyphicon-trash"></span></a>
|
||||
<a href="#" class="hover-button process-all-orphaned" data-bind="click: addAllOrphaned">$T('Glitter-retryAllOrphaned') <span class="glyphicon glyphicon-plus-sign"></span></a>
|
||||
<div class="clearfix"></div>
|
||||
<table class="table table-hover table-striped">
|
||||
<table class="table table-hover table-striped" aria-label="$T('Glitter-orphanedJobs')">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 30px;"></th>
|
||||
@@ -333,7 +336,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-6 control-label">$T('Glitter-interfaceRefresh')</label>
|
||||
<label class="col-sm-6 control-label" for="refreshRate-option">$T('Glitter-interfaceRefresh')</label>
|
||||
<div class="col-sm-4">
|
||||
<select id="refreshRate-option" class="form-control" data-bind="value: refreshRate">
|
||||
<option value="1">1 $T('second')</option>
|
||||
@@ -351,9 +354,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-6 control-label">$T('Glitter-queueItemLimit')</label>
|
||||
<label class="col-sm-6 control-label" for="queue-pagination-limit">$T('Glitter-queueItemLimit')</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="queue-pagination-limit" class="form-control" data-bind="value: queue.paginationLimit">
|
||||
<select name="queue-pagination-limit" id="queue-pagination-limit" class="form-control" data-bind="value: queue.paginationLimit">
|
||||
<option value="5">5 / $T('Glitter-page')</option>
|
||||
<option value="10">10 / $T('Glitter-page')</option>
|
||||
<option value="20">20 / $T('Glitter-page')</option>
|
||||
@@ -366,9 +369,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-6 control-label">$T('Glitter-historyItemLimit')</label>
|
||||
<label class="col-sm-6 control-label" for="history-pagination-limit">$T('Glitter-historyItemLimit')</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="history-pagination-limit" class="form-control" data-bind="value: history.paginationLimit">
|
||||
<select name="history-pagination-limit" id="history-pagination-limit" class="form-control" data-bind="value: history.paginationLimit">
|
||||
<option value="5">5 / $T('Glitter-page')</option>
|
||||
<option value="10">10 / $T('Glitter-page')</option>
|
||||
<option value="20">20 / $T('Glitter-page')</option>
|
||||
@@ -381,9 +384,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-6 control-label">$T('Glitter-dateFormat')</label>
|
||||
<label class="col-sm-6 control-label" for="general-date-format">$T('Glitter-dateFormat')</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="general-date-format" class="form-control" data-bind="value: dateFormat">
|
||||
<select name="general-date-format" id="general-date-format" class="form-control" data-bind="value: dateFormat">
|
||||
<option value="DD/MM/YYYY HH:mm"></option>
|
||||
<option value="DD/MM/YYYY h:mma"></option>
|
||||
<option value="MM/DD/YYYY HH:mm"></option>
|
||||
@@ -399,12 +402,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-6 control-label">
|
||||
<label class="col-sm-6 control-label" for="general-extra-queue-columns">
|
||||
$T('Glitter-showExtraQueueColumn')<br />
|
||||
<span class="label label-warning">> 1200 pixels</span>
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="general-extra-column" class="form-control-multiselect form-control" data-bind="selectedOptions: extraQueueColumns" multiple="true">
|
||||
<select name="general-extra-column" id="general-extra-queue-columns" class="form-control-multiselect form-control" data-bind="selectedOptions: extraQueueColumns" multiple="true">
|
||||
<option value="category">$T('category')</option>
|
||||
<option value="priority">$T('priority')</option>
|
||||
<option value="processing">$T('swtag-pp')</option>
|
||||
@@ -414,12 +417,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-6 control-label">
|
||||
<label class="col-sm-6 control-label" for="general-extra-history-columns">
|
||||
$T('Glitter-showExtraHistoryColumn')<br />
|
||||
<span class="label label-warning">> 1200 pixels</span>
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="general-extra-column" class="form-control-multiselect form-control" data-bind="selectedOptions: extraHistoryColumns" multiple="true">
|
||||
<select name="general-extra-column" id="general-extra-history-columns" class="form-control-multiselect form-control" data-bind="selectedOptions: extraHistoryColumns" multiple="true">
|
||||
<option value="category">$T('category')</option>
|
||||
<option value="size">$T('size')</option>
|
||||
<option value="speed">$T('Glitter-speed')</option>
|
||||
@@ -427,53 +430,53 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-checkbox">
|
||||
<label class="col-sm-6 control-label">
|
||||
<label class="col-sm-6 control-label" for="displayCompact">
|
||||
$T("Glitter-displayCompact")
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="checkbox" name="displayCompact" value="true" data-bind="checked: displayCompact" />
|
||||
<input type="checkbox" name="displayCompact" id="displayCompact" value="true" data-bind="checked: displayCompact" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-checkbox">
|
||||
<label class="col-sm-6 control-label">
|
||||
<label class="col-sm-6 control-label" for="displayFullWidth">
|
||||
$T("Glitter-displayFullWidth")
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="checkbox" name="displayFullWidth" value="true" data-bind="checked: displayFullWidth" />
|
||||
<input type="checkbox" name="displayFullWidth" id="displayFullWidth" value="true" data-bind="checked: displayFullWidth" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-checkbox">
|
||||
<label class="col-sm-6 control-label">
|
||||
<label class="col-sm-6 control-label" for="displayTabbed">
|
||||
$T("Glitter-displayTabbed")
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="checkbox" name="displayTabbed" value="true" data-bind="checked: displayTabbed" />
|
||||
<input type="checkbox" name="displayTabbed" id="displayTabbed" value="true" data-bind="checked: displayTabbed" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-checkbox">
|
||||
<label class="col-sm-6 control-label">
|
||||
<label class="col-sm-6 control-label" for="confirmDeleteQueue">
|
||||
$T("Glitter-confirmDeleteQueue")
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="checkbox" name="confirmDeleteQueue" value="true" data-bind="checked: confirmDeleteQueue" />
|
||||
<input type="checkbox" name="confirmDeleteQueue" id="confirmDeleteQueue" value="true" data-bind="checked: confirmDeleteQueue" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-checkbox">
|
||||
<label class="col-sm-6 control-label">
|
||||
<label class="col-sm-6 control-label" for="confirmDeleteHistory">
|
||||
$T("Glitter-confirmDeleteHistory")
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="checkbox" name="confirmDeleteHistory" value="true" data-bind="checked: confirmDeleteHistory" />
|
||||
<input type="checkbox" name="confirmDeleteHistory" id="confirmDeleteHistory" value="true" data-bind="checked: confirmDeleteHistory" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-checkbox">
|
||||
<label class="col-sm-6 control-label">
|
||||
<label class="col-sm-6 control-label" for="keyboardShortcuts">
|
||||
$T("Glitter-keyboardShortcuts")
|
||||
<span class="glyphicon glyphicon-question-sign" data-tooltip="true" data-placement="top" data-html="true"
|
||||
data-original-title="P: $T('link-pause')<br>A: $T('Glitter-addNZB')<br>S: $T('Glitter-statusInterfaceOptions')<br>C: $T('menu-config')<br>$T('Glitter-keyboardShortcuts-arrows')"></span>
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="checkbox" name="keyboardShortcuts" value="true" data-bind="checked: keyboardShortcuts" />
|
||||
<input type="checkbox" name="keyboardShortcuts" id="keyboardShortcuts" value="true" data-bind="checked: keyboardShortcuts" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -485,12 +488,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-add-nzb" class="modal fade" tabindex="-1">
|
||||
<div id="modal-add-nzb" class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-add-nzb-title">
|
||||
<div class="modal-dialog">
|
||||
<form class="modal-content" data-bind="submit: addNZB">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">$T('Glitter-addNZB')</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="modal-add-nzb-title">$T('Glitter-addNZB')</h4>
|
||||
</div>
|
||||
<div class="modal-body form-horizontal">
|
||||
<div class="row">
|
||||
@@ -524,29 +527,29 @@
|
||||
<div class="clearfix"></div>
|
||||
<hr />
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('name')</label>
|
||||
<label class="col-sm-4 control-label" for="nzbname">$T('name')</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="nzbname" id="nzbname" placeholder="$T('Glitter-addnzbFilename')" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('srv-password')</label>
|
||||
<label class="col-sm-4 control-label" for="password">$T('srv-password')</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="password" id="password" placeholder="$T('srv-optional')" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('category')</label>
|
||||
<label class="col-sm-4 control-label" for="add-nzb-category">$T('category')</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="Category" class="form-control" data-bind="options: queue.categoriesList, optionsValue: 'catValue', optionsText: 'catText', optionsCaption: ''"></select>
|
||||
<select name="Category" id="add-nzb-category" class="form-control" data-bind="options: queue.categoriesList, optionsValue: 'catValue', optionsText: 'catText', optionsCaption: ''"></select>
|
||||
<span class="glyphicon glyphicon-tag"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('priority')</label>
|
||||
<label class="col-sm-4 control-label" for="add-nzb-priority">$T('priority')</label>
|
||||
<div class="col-sm-6">
|
||||
<!-- This list is different from the one during download! -->
|
||||
<select name="Priority" class="form-control">
|
||||
<select name="Priority" id="add-nzb-priority" class="form-control">
|
||||
<option value=""></option>
|
||||
<option value="2">$T('pr-force')</option>
|
||||
<option value="1">$T('pr-high')</option>
|
||||
@@ -558,16 +561,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('swtag-pp')</label>
|
||||
<label class="col-sm-4 control-label" for="add-nzb-processing">$T('swtag-pp')</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="Processing" class="form-control" data-bind="options: queue.processingOptions, optionsValue: 'value', optionsText: 'name', optionsCaption: ''"></select>
|
||||
<select name="Processing" id="add-nzb-processing" class="form-control" data-bind="options: queue.processingOptions, optionsValue: 'value', optionsText: 'name', optionsCaption: ''"></select>
|
||||
<span class="glyphicon glyphicon-check"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">$T('eoq-scripts')</label>
|
||||
<label class="col-sm-4 control-label" for="add-nzb-script">$T('eoq-scripts')</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="Post-processing" class="form-control" data-bind="options: queue.scriptsList, optionsCaption: '', optionsValue: 'scriptValue', optionsText: 'scriptText', enable: (queue.scriptsList().length > 1)"></select>
|
||||
<select name="Post-processing" id="add-nzb-script" class="form-control" data-bind="options: queue.scriptsList, optionsCaption: '', optionsValue: 'scriptValue', optionsText: 'scriptText', enable: (queue.scriptsList().length > 1)"></select>
|
||||
<span class="glyphicon glyphicon-flash"></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -577,12 +580,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-item-files" class="modal fade" tabindex="-1">
|
||||
<div id="modal-item-files" class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-item-files-title">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title row-wrap-text" data-bind="text: filelist.filelist_name">$T('Glitter-loading')</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title row-wrap-text" id="modal-item-files-title" data-bind="text: filelist.filelist_name">$T('Glitter-loading')</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="modal-item-filelist">
|
||||
@@ -645,12 +648,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-delete-queue-job" class="modal modal-delete-job fade" tabindex="-1">
|
||||
<div id="modal-delete-queue-job" class="modal modal-delete-job fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-delete-queue-job-title">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title row-wrap-text">$T('removeNZB-Files')</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title row-wrap-text" id="modal-delete-queue-job-title">$T('removeNZB-Files')</h4>
|
||||
</div>
|
||||
<form data-bind="submit: queue.removeDownloads">
|
||||
<div class="modal-body">
|
||||
@@ -669,12 +672,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-delete-history-job" class="modal modal-delete-job fade" tabindex="-1">
|
||||
<div id="modal-delete-history-job" class="modal modal-delete-job fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-delete-history-job-title">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title row-wrap-text">$T('nzo-delete')</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title row-wrap-text" id="modal-delete-history-job-title">$T('nzo-delete')</h4>
|
||||
</div>
|
||||
<form data-bind="submit: history.removeDownloads">
|
||||
<div class="modal-body">
|
||||
@@ -698,12 +701,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-retry-job" class="modal modal-small fade" tabindex="-1">
|
||||
<div id="modal-retry-job" class="modal modal-small fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-retry-job-title">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">$T('Glitter-retryJob')</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="modal-retry-job-title">$T('Glitter-retryJob')</h4>
|
||||
</div>
|
||||
<form id="retry-job-form" data-bind="submit: history.retryJob">
|
||||
<div class="modal-body">
|
||||
@@ -740,24 +743,24 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="history-script-log" class="modal fade" tabindex="-1">
|
||||
<div id="history-script-log" class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="history-script-log-title">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">$T('Glitter-scriptLog')</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="history-script-log-title">$T('Glitter-scriptLog')</h4>
|
||||
</div>
|
||||
<div class="modal-body"></div>
|
||||
<div class="modal-body"><pre></pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-help" class="modal fade">
|
||||
<div id="modal-help" class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-help-title">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">$T('menu-help')</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="modal-help-title">$T('menu-help')</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
#include $webdir + "/../../Config/templates/staticcfg/images/logo-full.svg"#
|
||||
@@ -790,12 +793,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-purge-history" class="modal modal-small fade" tabindex="-1">
|
||||
<div id="modal-purge-history" class="modal modal-small fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-purge-history-title">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">$T('Glitter-clearHistory')</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="modal-purge-history-title">$T('Glitter-clearHistory')</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<button type="button" class="btn btn-danger" data-bind="click: history.emptyHistory" data-action="history-purge-failed"><span class="glyphicon glyphicon-floppy-remove"></span> $T('purgeFailed')</button>
|
||||
@@ -814,12 +817,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-custom-pause" class="modal modal-small fade" tabindex="-1">
|
||||
<div id="modal-custom-pause" class="modal modal-small fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-custom-pause-title">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">$T('Glitter-pauseFor')</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="modal-custom-pause-title">$T('Glitter-pauseFor')</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form data-bind="submit: saveCustomPause">
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
</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="sortRemainingBytesAsc" data-bind="click: queue.queueSorting">$T('Glitter-sortRemainingBytesAsc')</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>
|
||||
@@ -57,17 +58,17 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<table class="table table-striped table-hover queue-table">
|
||||
<table class="table table-striped table-hover queue-table" aria-label="$T('menu-queue')">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 25px;"></th>
|
||||
<th></th>
|
||||
<th scope="col" style="width: 25px;"><span class="sr-only">$T('status')</span></th>
|
||||
<th scope="col"><span class="sr-only">$T('name')</span></th>
|
||||
<!-- ko foreach: extraQueueColumns -->
|
||||
<th class="table-header-extra"></th>
|
||||
<th class="table-header-extra" scope="col"><span class="sr-only" data-bind="text: glitterTranslate.column[\$data]"></span></th>
|
||||
<!-- /ko -->
|
||||
<th class="table-header-progress" data-bind="css: { 'table-header-progress-smaller' : extraQueueColumns().length }"></th>
|
||||
<th style="width: 85px;"></th>
|
||||
<th style="width: 60px;"></th>
|
||||
<th class="table-header-progress" scope="col" data-bind="css: { 'table-header-progress-smaller' : extraQueueColumns().length || displayCompact() }"><span class="sr-only">$T('Glitter-progress')</span></th>
|
||||
<th scope="col" style="width: 85px;"><span class="sr-only">$T('status')</span></th>
|
||||
<th scope="col" style="width: 60px;"><span class="sr-only">$T('Glitter-actions')</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!-- ko if: !hasQueue() -->
|
||||
@@ -84,7 +85,7 @@
|
||||
<tbody data-bind="visible: hasQueue(), sortable: { data: queue.queueItems, afterMove: queue.move, options: { start: queue.dragStart, stop: queue.dragStop, axis: 'y', containment: '.queue', distance: 10 } }" style="display: none;">
|
||||
<tr class="queue-item">
|
||||
<td>
|
||||
<a href="#" data-bind="click: pauseToggle, attr: { 'title': pausedStatus() ? '$T('link-resume')' : '$T('link-pause')' }">
|
||||
<a href="#" data-bind="click: pauseToggle, attr: { 'title': pausedStatus() ? '$T('link-resume')' : '$T('link-pause')', 'aria-label': pausedStatus() ? '$T('link-resume')' : '$T('link-pause')' }">
|
||||
<span class="hover-button glyphicon" data-bind="css: queueIcon"></span>
|
||||
</a>
|
||||
</td>
|
||||
@@ -102,27 +103,41 @@
|
||||
<!-- /ko -->
|
||||
</div>
|
||||
<form data-bind="submit: editingNameSubmit">
|
||||
<input type="text" data-bind="value: nameForEdit, visible: editingName(), hasfocus: editingName" />
|
||||
<input type="text" aria-label="$T('Glitter-rename')" data-bind="value: nameForEdit, visible: editingName(), hasfocus: editingName" />
|
||||
</form>
|
||||
<div class="name-icons direct-unpack hover-button" data-bind="visible: direct_unpack() && !editingName()">
|
||||
<span class="glyphicon glyphicon-compressed"></span> <span data-bind="text: direct_unpack"></span>
|
||||
</div>
|
||||
<div class="name-options" data-bind="visible: !editingName(), css: { disabled: isGrabbing() }">
|
||||
<a href="#" data-bind="click: \$parent.queue.moveButton" class="hover-button buttonMoveToTop" title="$T('Glitter-top')"><span class="glyphicon glyphicon-chevron-up"></span></a>
|
||||
<a href="#" data-bind="click: \$parent.queue.moveButton" class="hover-button buttonMoveToBottom" title="$T('Glitter-bottom')"><span class="glyphicon glyphicon-chevron-down"></span></a>
|
||||
<a href="#" data-bind="click: editName" class="hover-button" title="$T('Glitter-rename')"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a href="#" data-bind="click: showFiles" class="hover-button" title="$T('nzoDetails') - $T('srv-password')"><span class="glyphicon glyphicon-folder-open"></span></a>
|
||||
<a href="#" data-bind="click: \$parent.queue.moveButton" class="hover-button buttonMoveToTop" title="$T('Glitter-top')" aria-label="$T('Glitter-top')"><span class="glyphicon glyphicon-chevron-up"></span></a>
|
||||
<a href="#" data-bind="click: \$parent.queue.moveButton" class="hover-button buttonMoveToBottom" title="$T('Glitter-bottom')" aria-label="$T('Glitter-bottom')"><span class="glyphicon glyphicon-chevron-down"></span></a>
|
||||
<a href="#" data-bind="click: editName" class="hover-button" title="$T('Glitter-rename')" aria-label="$T('Glitter-rename')"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a href="#" data-bind="click: showFiles" class="hover-button" title="$T('nzoDetails') - $T('srv-password')" aria-label="$T('nzoDetails')"><span class="glyphicon glyphicon-folder-open"></span></a>
|
||||
<small data-bind="text: avg_age"></small>
|
||||
</div>
|
||||
</td>
|
||||
<!-- ko foreach: parent.parent.extraQueueColumns -->
|
||||
<td class="row-extra-text">
|
||||
<!-- ko if: \$data == 'category' -->
|
||||
<select class="form-control row-extra-select" data-bind="options: \$parent.parent.categoriesList, optionsValue: 'catValue', optionsText: 'catText', value: \$parent.category, valueAllowUnset: true, event: { change: \$parent.changeCat }"></select>
|
||||
<!-- /ko -->
|
||||
<!-- ko if: \$data == 'priority' && !\$parent.isFetchingBlocks -->
|
||||
<select class="form-control row-extra-select" data-bind="options: \$parent.parent.priorityOptions, optionsValue: 'value', optionsText: 'name', value: \$parent.priority, valueAllowUnset: true, event: { change: \$parent.changePriority }"></select>
|
||||
<!-- /ko -->
|
||||
<!-- ko if: \$data == 'processing' -->
|
||||
<select class="form-control row-extra-select" data-bind="options: \$parent.parent.processingOptions, optionsValue: 'value', optionsText: 'name', value: \$parent.unpackopts, valueAllowUnset: true, event: { change: \$parent.changeProcessing }"></select>
|
||||
<!-- /ko -->
|
||||
<!-- ko if: \$data == 'scripts' -->
|
||||
<select class="form-control row-extra-select" data-bind="options: \$parent.parent.scriptsList, optionsValue: 'scriptValue', optionsText: 'scriptText', value: \$parent.script, valueAllowUnset: true, event: { change: \$parent.changeScript }, enable: (\$parent.parent.scriptsList().length > 1)"></select>
|
||||
<!-- /ko -->
|
||||
<!-- ko if: \$data == 'age' -->
|
||||
<div class="row-wrap-text" data-bind="text: \$parent.showColumn(\$data)"></div>
|
||||
<!-- /ko -->
|
||||
</td>
|
||||
<!-- /ko -->
|
||||
<td class="progress-indicator">
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-info" data-bind="attr: { 'style': 'width: ' + percentage() + '%; background-color: ' + progressColor() + ';' }">
|
||||
<div class="progress-bar progress-bar-info" role="progressbar" aria-label="$T('Glitter-progress')" aria-valuemin="0" aria-valuemax="100" data-bind="attr: { 'style': 'width: ' + percentage() + '%; background-color: ' + progressColor() + ';', 'aria-valuenow': percentage() }">
|
||||
<strong data-bind="text: percentage() + '%'"></strong>
|
||||
<i data-bind="text: missingText"></i>
|
||||
</div>
|
||||
@@ -132,65 +147,65 @@
|
||||
<td class="timeleft row-wrap-text" data-bind="text: statusText"></td>
|
||||
<td class="delete">
|
||||
<label data-bind="visible: parent.isMultiEditing()">
|
||||
<input type="checkbox" name="multiedit" title="$T('Glitter-multiSelect')" data-bind="click: parent.addMultiEdit, attr: { 'id': 'multiedit_' + id } " />
|
||||
<input type="checkbox" name="multiedit" title="$T('Glitter-multiSelect')" aria-label="$T('Glitter-selectJob')" data-bind="click: parent.addMultiEdit, attr: { 'id': 'multiedit_' + id } " />
|
||||
</label>
|
||||
<!-- ko if: !isGrabbing() -->
|
||||
<div class="dropdown" data-bind="visible: !parent.isMultiEditing()">
|
||||
<a href="#" data-toggle="dropdown" data-bind="click: toggleDropdown">
|
||||
<a href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="$T('nzoDetails')" data-bind="click: toggleDropdown">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<!-- ko if: hasDropdown() -->
|
||||
<ul class="dropdown-menu queue-item-settings">
|
||||
<li title="$T('category')" data-tooltip="true" data-placement="left">
|
||||
<span class="glyphicon glyphicon-tag"></span>
|
||||
<select name="Category" class="form-control" data-bind="options: parent.categoriesList, optionsValue: 'catValue', optionsText: 'catText', value: category, event: { change: changeCat }"></select>
|
||||
<select name="Category" class="form-control" aria-label="$T('category')" data-bind="options: parent.categoriesList, optionsValue: 'catValue', optionsText: 'catText', value: category, valueAllowUnset: true, event: { change: changeCat }"></select>
|
||||
</li>
|
||||
<!-- ko if: !isFetchingBlocks -->
|
||||
<li title="$T('priority')" data-tooltip="true" data-placement="left">
|
||||
<span class="glyphicon glyphicon-sort-by-attributes-alt"></span>
|
||||
<select name="Priority" class="form-control" data-bind="options: parent.priorityOptions, optionsValue: 'value', optionsText: 'name', value: priority, event: { change: changePriority }"></select>
|
||||
<select name="Priority" class="form-control" aria-label="$T('priority')" data-bind="options: parent.priorityOptions, optionsValue: 'value', optionsText: 'name', value: priority, valueAllowUnset: true, event: { change: changePriority }"></select>
|
||||
</li>
|
||||
<!-- /ko -->
|
||||
<li title="$T('swtag-pp')" data-tooltip="true" data-placement="left">
|
||||
<span class="glyphicon glyphicon-check"></span>
|
||||
<select name="Processing" class="form-control" data-bind="options: parent.processingOptions, optionsValue: 'value', optionsText: 'name', value: unpackopts, event: { change: changeProcessing }"></select>
|
||||
<select name="Processing" class="form-control" aria-label="$T('swtag-pp')" data-bind="options: parent.processingOptions, optionsValue: 'value', optionsText: 'name', value: unpackopts, valueAllowUnset: true, event: { change: changeProcessing }"></select>
|
||||
</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, optionsValue: 'scriptValue', optionsText: 'scriptText', event: { change: changeScript }, enable: (parent.scriptsList().length > 1)"></select>
|
||||
<select name="Post-processing" class="form-control" aria-label="$T('eoq-scripts')" data-bind="options: parent.scriptsList, value: script, valueAllowUnset: true, optionsValue: 'scriptValue', optionsText: 'scriptText', event: { change: changeScript }, enable: (parent.scriptsList().length > 1)"></select>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- /ko -->
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<a href="#" class="hover-button" title="$T('removeNZB-Files')" data-bind="click: parent.triggerRemoveDownload"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
<a href="#" class="hover-button" title="$T('removeNZB-Files')" aria-label="$T('removeNZB-Files')" data-bind="click: parent.triggerRemoveDownload"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="queue-footer">
|
||||
|
||||
<form class="multioperations-selector" data-bind="visible: (hasQueue() && queue.isMultiEditing())" style="display: none;">
|
||||
<div class="add-nzb-inputbox add-nzb-inputbox-small add-nzb-inputbox-options">
|
||||
<label for="multiedit-checkall-queue">
|
||||
<input type="checkbox" name="multieditCheckAll" id="multiedit-checkall-queue" title="$T('Glitter-checkAll')" data-bind="click: queue.checkAllJobs" data-tooltip="true" data-placement="top" />
|
||||
<input type="checkbox" name="multieditCheckAll" id="multiedit-checkall-queue" title="$T('Glitter-checkAll')" aria-label="$T('Glitter-checkAll')" data-bind="click: queue.checkAllJobs" data-tooltip="true" data-placement="top" />
|
||||
</label>
|
||||
<a href="#" class="hover-button" title="$T('removeNZB-Files')" data-bind="click: queue.doMultiDelete" data-tooltip="true" data-placement="top">
|
||||
<a href="#" class="hover-button" title="$T('removeNZB-Files')" aria-label="$T('Glitter-removeSelected')" data-bind="click: queue.doMultiDelete" data-tooltip="true" data-placement="top">
|
||||
<span class="glyphicon glyphicon-trash"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="add-nzb-inputbox add-nzb-inputbox-small">
|
||||
<label for="multiedit-play" data-bind="event: { mousedown: queue.handleMultiEditStatusMouseDown }">
|
||||
<input type="radio" name="multiedit-status" value="resume" id="multiedit-play" data-bind="event: { change: queue.doMultiEditUpdate }" />
|
||||
<input type="radio" name="multiedit-status" value="resume" id="multiedit-play" aria-label="$T('link-resume')" data-bind="event: { change: queue.doMultiEditUpdate }" />
|
||||
<span class="glyphicon glyphicon-play" title="$T('link-resume')" data-tooltip="true" data-placement="top"></span>
|
||||
</label>
|
||||
<label for="multiedit-pause" data-bind="event: { mousedown: queue.handleMultiEditStatusMouseDown }">
|
||||
<input type="radio" name="multiedit-status" value="pause" id="multiedit-pause" data-bind="event: { change: queue.doMultiEditUpdate }" />
|
||||
<input type="radio" name="multiedit-status" value="pause" id="multiedit-pause" aria-label="$T('link-pause')" data-bind="event: { change: queue.doMultiEditUpdate }" />
|
||||
<span class="glyphicon glyphicon-pause" title="$T('link-pause')" data-tooltip="true" data-placement="top"></span>
|
||||
</label>
|
||||
<a href="#" class="hover-button" title="$T('Glitter-top')" data-bind="click: queue.doMultiMoveToTop" data-tooltip="true" data-placement="top">
|
||||
<a href="#" class="hover-button" title="$T('Glitter-top')" aria-label="$T('Glitter-top')" data-bind="click: queue.doMultiMoveToTop" data-tooltip="true" data-placement="top">
|
||||
<span class="glyphicon glyphicon-chevron-up"></span>
|
||||
</a>
|
||||
<a href="#" class="hover-button" title="$T('Glitter-bottom')" data-bind="click: queue.doMultiMoveToBottom" data-tooltip="true" data-placement="top">
|
||||
<a href="#" class="hover-button" title="$T('Glitter-bottom')" aria-label="$T('Glitter-bottom')" data-bind="click: queue.doMultiMoveToBottom" data-tooltip="true" data-placement="top">
|
||||
<span class="glyphicon glyphicon-chevron-down"></span>
|
||||
</a>
|
||||
<span class="label label-default" data-bind="text: queue.multiEditItems().length">0</span>
|
||||
@@ -198,33 +213,40 @@
|
||||
<div class="add-nzb-inputbox-clear"></div>
|
||||
<div class="add-nzb-inputbox" data-tooltip="true" data-placement="top" title="$T('category')">
|
||||
<span class="glyphicon glyphicon-tag"></span>
|
||||
<select name="Category" class="form-control" data-bind="options: queue.categoriesList, optionsValue: 'catValue', optionsText: 'catText', optionsCaption: '', event: { change: queue.doMultiEditUpdate }"></select>
|
||||
<select name="Category" class="form-control" aria-label="$T('category')" data-bind="options: queue.categoriesList, optionsValue: 'catValue', optionsText: 'catText', optionsCaption: '', event: { change: queue.doMultiEditUpdate }"></select>
|
||||
</div>
|
||||
<div class="add-nzb-inputbox" data-tooltip="true" data-placement="top" title="$T('priority')">
|
||||
<span class="glyphicon glyphicon-sort-by-attributes-alt"></span>
|
||||
<select name="Priority" class="form-control" data-bind="options: queue.priorityOptions, optionsValue: 'value', optionsText: 'name', optionsCaption: '', event: { change: queue.doMultiEditUpdate }"></select>
|
||||
<select name="Priority" class="form-control" aria-label="$T('priority')" data-bind="options: queue.priorityOptions, optionsValue: 'value', optionsText: 'name', optionsCaption: '', event: { change: queue.doMultiEditUpdate }"></select>
|
||||
</div>
|
||||
<div class="add-nzb-inputbox" data-tooltip="true" data-placement="top" title="$T('swtag-pp')">
|
||||
<span class="glyphicon glyphicon-check"></span>
|
||||
<select name="Processing" class="form-control" data-bind="options: queue.processingOptions, optionsValue: 'value', optionsText: 'name', optionsCaption: '', event: { change: queue.doMultiEditUpdate }"></select>
|
||||
<select name="Processing" class="form-control" aria-label="$T('swtag-pp')" data-bind="options: queue.processingOptions, optionsValue: 'value', optionsText: 'name', optionsCaption: '', event: { change: queue.doMultiEditUpdate }"></select>
|
||||
</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, optionsValue: 'scriptValue', optionsText: 'scriptText', optionsCaption: '', event: { change: queue.doMultiEditUpdate }"></select>
|
||||
<select name="Post-processing" class="form-control" aria-label="$T('eoq-scripts')" data-bind="options: queue.scriptsList, optionsValue: 'scriptValue', optionsText: 'scriptText', optionsCaption: '', event: { change: queue.doMultiEditUpdate }"></select>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</form>
|
||||
|
||||
<div class="input-group search-box" data-bind="visible: queue.hasQueueSearch" style="display: none;">
|
||||
<input type="text" class="form-control" placeholder="$T('Glitter-search')" required data-bind="textInput: queue.searchTerm, event: { keydown: queue.clearSearchTerm }" />
|
||||
<a data-bind="event: { mousedown: queue.clearSearchTerm }">
|
||||
<input type="text" class="form-control" placeholder="$T('Glitter-search')" aria-label="$T('Glitter-search')" required data-bind="textInput: queue.searchTerm, event: { keydown: queue.clearSearchTerm }" />
|
||||
<a href="#" data-tooltip="true" data-html="true" data-placement="right" title="$T('Glitter-searchExplain')" data-bind="click: queue.clearSearchTerm, attr: { 'aria-label': queue.searchTerm() ? '$T('Glitter-clearSearch')' : '$T('Glitter-search')' }">
|
||||
<span class="glyphicon" data-bind="css: { 'glyphicon-search' : !queue.searchTerm(), 'glyphicon-remove' : queue.searchTerm() }"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="pagination" data-bind="foreach: queue.pagination.allpages, visible: queue.pagination.hasPagination" style="display: none;">
|
||||
<li data-bind="css: { active: isCurrent, disabled: isDots }, click: onclick">
|
||||
<span data-bind="text: page"></span>
|
||||
<li data-bind="css: { active: isCurrent, disabled: isDots }">
|
||||
<!-- ko ifnot: isDots -->
|
||||
<a href="#" data-bind="text: page, click: onclick, attr: { 'aria-current': isCurrent ? 'page' : null }"></a>
|
||||
<!-- /ko -->
|
||||
<!-- ko if: isDots -->
|
||||
<span aria-hidden="true" data-bind="text: page"></span>
|
||||
<!-- /ko -->
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div><!-- /.queue-footer -->
|
||||
</div>
|
||||
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<!--#set $active_lang=$active_lang.replace('_', '-').lower()#-->
|
||||
<html lang="$active_lang" <!--#if $rtl#-->dir="rtl"<!--#end if#--> id="sabnzbd" data-bind="filedrop: { overlaySelector: '.main-filedrop', onFileDrop: addNZBFromFile }">
|
||||
<html lang="$active_lang" <!--#if $rtl#-->dir="rtl"<!--#end if#--> id="sabnzbd" data-color-scheme="$color_scheme" data-bind="filedrop: { overlaySelector: '.main-filedrop', onFileDrop: addNZBFromFile }">
|
||||
<head>
|
||||
<!--
|
||||
Glitter V2
|
||||
@@ -25,25 +25,23 @@
|
||||
<meta name="msapplication-navbutton-color" content="#000000" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="./staticcfg/ico/apple-touch-icon-76x76-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="./staticcfg/ico/apple-touch-icon-120x120-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="./staticcfg/ico/apple-touch-icon-152x152-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="./staticcfg/ico/apple-touch-icon-180x180-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./staticcfg/ico/android-192x192.png" />
|
||||
<link rel="mask-icon" href="./staticcfg/ico/safari-pinned-tab.svg" color="#383F45">
|
||||
<link rel="shortcut icon" type="image/ico" href="./staticcfg/ico/favicon.ico?v=$version" data-bind="attr: { 'href': SABIcon }" />
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="$url('staticcfg/ico/apple-touch-icon-76x76-precomposed.png', v=$cache_buster)" />
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="$url('staticcfg/ico/apple-touch-icon-120x120-precomposed.png', v=$cache_buster)" />
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="$url('staticcfg/ico/apple-touch-icon-152x152-precomposed.png', v=$cache_buster)" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="$url('staticcfg/ico/apple-touch-icon-180x180-precomposed.png', v=$cache_buster)" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="$url('staticcfg/ico/android-192x192.png', v=$cache_buster)" />
|
||||
<link rel="mask-icon" href="$url('staticcfg/ico/safari-pinned-tab.svg', v=$cache_buster)" color="#383F45">
|
||||
<link rel="shortcut icon" type="image/ico" href="$url('staticcfg/ico/favicon.ico', v=$cache_buster)" data-bind="attr: { 'href': SABIcon }" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./static/bootstrap/css/bootstrap.min.css?v=$version" />
|
||||
<link rel="stylesheet" type="text/css" href="./static/stylesheets/glitter.css?v=$version" />
|
||||
<link rel="stylesheet" type="text/css" href="./static/stylesheets/glitter.mobile.css?v=$version" media="all and (max-width: 768px)" />
|
||||
<!--#if $color_scheme not in ('Light', '') #-->
|
||||
<link rel="stylesheet" type="text/css" href="./static/stylesheets/colorschemes/${color_scheme}.css?v=$version"/>
|
||||
<!--#end if#-->
|
||||
<link rel="stylesheet" type="text/css" href="$url('static/bootstrap/css/bootstrap.min.css', v=$cache_buster)" />
|
||||
<link rel="stylesheet" type="text/css" href="$url('static/stylesheets/glitter.css', v=$cache_buster)" />
|
||||
<link rel="stylesheet" type="text/css" href="$url('static/stylesheets/glitter.mobile.css', v=$cache_buster)" media="all and (max-width: 768px)" />
|
||||
|
||||
<!-- Make translations available in scripts -->
|
||||
<script type="text/javascript">
|
||||
var apiKey = "$apikey";
|
||||
var csrfToken = "$csrf_token";
|
||||
var displayLang = "$active_lang";
|
||||
var dateScriptUrl = "$url('static/javascripts/date.min.js', v=$cache_buster)";
|
||||
var sabSpeedHistory = [$bytespersec_list];
|
||||
var newRelease = "$new_release";
|
||||
var newReleaseUrl = "$new_rel_url";
|
||||
@@ -76,7 +74,14 @@
|
||||
glitterTranslate.defaultText = "$T('default')";
|
||||
glitterTranslate.noneText = "$T('None')";
|
||||
glitterTranslate.moreText = "$T('Glitter-more')";
|
||||
|
||||
glitterTranslate.column = [];
|
||||
glitterTranslate.column['category'] = "$T('category')";
|
||||
glitterTranslate.column['priority'] = "$T('priority')";
|
||||
glitterTranslate.column['processing'] = "$T('swtag-pp')";
|
||||
glitterTranslate.column['scripts'] = "$T('eoq-scripts')";
|
||||
glitterTranslate.column['age'] = "$T('nzo-age')";
|
||||
glitterTranslate.column['size'] = "$T('size')";
|
||||
glitterTranslate.column['speed'] = "$T('Glitter-speed')";
|
||||
glitterTranslate.status = [];
|
||||
glitterTranslate.status['DirectUnpack'] = "$T('opt-direct_unpack')";
|
||||
glitterTranslate.status['Completed'] = "$T('post-Completed')";
|
||||
@@ -117,21 +122,27 @@
|
||||
glitterTranslate.priority['Stop'] = "$T('pr-stop')";
|
||||
</script>
|
||||
|
||||
<!-- Inclusion is faster than external scripts. We load momentJS locale separately so failure won't break anything -->
|
||||
<script type="text/javascript" src="$url('staticcfg/js/jquery-3.7.1.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('staticcfg/js/jquery-ui.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('static/javascripts/jquery.peity.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('static/javascripts/jquery.hotkeys.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('static/javascripts/moment-2.26.0.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('static/javascripts/knockout-3.5.1.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('static/javascripts/knockout-extensions.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('static/javascripts/search-query-parser.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('staticcfg/bootstrap/js/bootstrap.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('static/javascripts/glitter.basic.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('static/javascripts/glitter.main.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('static/javascripts/glitter.queue.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('static/javascripts/glitter.history.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('static/javascripts/glitter.filelist.pagination.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript">
|
||||
<!--#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"#-->
|
||||
jQuery(function () {
|
||||
ko.applyBindings(new ViewModel(), document.getElementById("sabnzbd"));
|
||||
});
|
||||
</script>
|
||||
<!--#if active_lang != 'en'#-->
|
||||
<script type="text/javascript" src="./static/javascripts/momentjs_locale/${active_lang}.js"></script>
|
||||
<script type="text/javascript" src="$url('static/javascripts/momentjs_locale/' + $active_lang + '.js', v=$cache_buster)"></script>
|
||||
<!--#end if#-->
|
||||
</head>
|
||||
<body>
|
||||
@@ -139,21 +150,21 @@
|
||||
<!--#include $webdir + "/include_menu.tmpl"#-->
|
||||
</div>
|
||||
|
||||
<div class="container main-content">
|
||||
<div class="history-queue-swicher">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active">
|
||||
<a href="#queue-tab" data-toggle="tab">$T('menu-queue') <span class="badge" data-bind="text: queue.totalItems"></span></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#history-tab" data-toggle="tab">$T('menu-history') <span class="badge badge-info" data-bind="text: history.ppItems, visible: history.ppItems"></span><span class="badge" data-bind="text: history.totalItems"></span></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#queue-messages" data-toggle="tab">$T('warnings') <span class="badge" data-bind="text: hasMessages, css: { 'badge-warning': hasMessages() }"></span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="container history-queue-swicher">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active">
|
||||
<a href="#queue-tab" data-toggle="tab">$T('menu-queue') <span class="badge" data-bind="text: queue.totalItems"></span></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#history-tab" data-toggle="tab">$T('menu-history') <span class="badge badge-info" data-bind="text: history.ppItems, visible: history.ppItems"></span><span class="badge" data-bind="text: history.totalItems"></span></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#queue-messages" data-toggle="tab">$T('warnings') <span class="badge" data-bind="text: hasMessages, css: { 'badge-warning': hasMessages() }"></span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="container main-content" data-bind="css: { 'main-content-loaded': isLoaded }">
|
||||
<!--#include $webdir + "/include_queue.tmpl"#-->
|
||||
<!--#include $webdir + "/include_messages.tmpl"#-->
|
||||
<!--#include $webdir + "/include_history.tmpl"#-->
|
||||
|
||||
File diff suppressed because one or more lines are too long.
@@ -23,15 +23,17 @@ if(isMobile) {
|
||||
});
|
||||
}
|
||||
|
||||
$.ajaxSetup({
|
||||
headers: { "X-SABnzbd-CSRF": csrfToken }
|
||||
});
|
||||
|
||||
// Basic API-call
|
||||
function callAPI(data, timeout = 10000) {
|
||||
// Fill basis var's
|
||||
data.output = "json";
|
||||
data.apikey = apiKey;
|
||||
var ajaxQuery = $.ajax({
|
||||
url: "./api",
|
||||
type: "GET",
|
||||
cache: false,
|
||||
type: "POST",
|
||||
data: data,
|
||||
timeout: timeout
|
||||
});
|
||||
|
||||
@@ -150,7 +150,6 @@ function HistoryListModel(parent) {
|
||||
data.append("nzbfile", $(form.nzbFile)[0].files[0]);
|
||||
data.append("value", $('#modal-retry-job input[name="retry_job_id"]').val());
|
||||
data.append("password", $('#retry_job_password').val());
|
||||
data.append("apikey", apiKey);
|
||||
|
||||
// Add
|
||||
$.ajax({
|
||||
@@ -184,15 +183,15 @@ function HistoryListModel(parent) {
|
||||
// Clear searchterm
|
||||
self.clearSearchTerm = function(data, event) {
|
||||
// Was it escape key or click?
|
||||
if(event.type === 'mousedown' || (event.keyCode && event.keyCode === 27)) {
|
||||
if(event.type === 'click' || (event.keyCode && event.keyCode === 27)) {
|
||||
// Set the loader so it doesn't flicker and then switch
|
||||
self.isLoading(true)
|
||||
self.searchTerm('');
|
||||
}
|
||||
// Was it click and the field is empty? Then we focus on the field
|
||||
if(event.type === 'mousedown' && self.searchTerm() === '') {
|
||||
if(event.type === 'click' && self.searchTerm() === '') {
|
||||
$(event.target).parents('.search-box').find('input[type="text"]').focus()
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
// Need to return true to allow typing
|
||||
return true;
|
||||
@@ -638,14 +637,13 @@ function HistoryModel(parent, data) {
|
||||
$(this).hide()
|
||||
} else {
|
||||
// Info in modal
|
||||
$('#history-script-log .modal-body').load($(this).attr('href'), function(result) {
|
||||
// Set title and then remove it
|
||||
$('#history-script-log .modal-title').text($(this).find("h3").text())
|
||||
$(this).find("h3, title").remove()
|
||||
$('#history-script-log').modal('show');
|
||||
$('#history-script-log .modal-body pre').load($(this).attr('href'), function(result) {
|
||||
var modal = $('#history-script-log');
|
||||
modal.find('.modal-title').text(self.historyStatus.name());
|
||||
modal.modal('show');
|
||||
});
|
||||
}
|
||||
return false;
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/******
|
||||
|
||||
Glitter V1
|
||||
By Safihre (2015) - safihre@sabnzbd.org
|
||||
|
||||
Code extended from Shiny-template
|
||||
Code examples used from Knockstrap-template
|
||||
|
||||
The setup is hierarchical, 1 main ViewModel that contains:
|
||||
- ViewModel
|
||||
- QueueListModel
|
||||
- paginationModel
|
||||
- QueueModel (item 1)
|
||||
- QueueModel (item 2)
|
||||
- ...
|
||||
- QueueModel (item n+1)
|
||||
- HistoryListModel
|
||||
- paginationModel
|
||||
- HistoryModel (item 1)
|
||||
- HistoryModel (item 2)
|
||||
- ...
|
||||
- HistoryModel (item n+1)
|
||||
- Fileslisting
|
||||
- FileslistingModel (file 1)
|
||||
- FileslistingModel (file 2)
|
||||
- ...
|
||||
- FileslistingModel (file n+1)
|
||||
|
||||
ViewModel also contains all the code executed on document ready and
|
||||
functions responsible for the status information, adding NZB, etc.
|
||||
The QueueModel/HistoryModel's get added to the list-models when
|
||||
jobs are added or on switching of pages (using paginationModel).
|
||||
Once added only the properties that changed during a refresh
|
||||
get updated. In the history all the detailed information is only
|
||||
updated when created and when the user clicks on a detail.
|
||||
The Fileslisting is only populated and updated when it is opened
|
||||
for one of the QueueModel's.
|
||||
|
||||
******/
|
||||
|
||||
#include raw $webdir + "/static/javascripts/glitter.basic.js"#
|
||||
|
||||
/**
|
||||
GLITTER CODE
|
||||
**/
|
||||
\$(function() {
|
||||
'use strict';
|
||||
|
||||
#include raw $webdir + "/static/javascripts/glitter.main.js"#
|
||||
#include raw $webdir + "/static/javascripts/glitter.queue.js"#
|
||||
#include raw $webdir + "/static/javascripts/glitter.history.js"#
|
||||
#include raw $webdir + "/static/javascripts/glitter.filelist.pagination.js"#
|
||||
|
||||
// GO!!!
|
||||
ko.applyBindings(new ViewModel(), document.getElementById("sabnzbd"));
|
||||
});
|
||||
@@ -10,6 +10,7 @@ function ViewModel() {
|
||||
|
||||
// Set status varibales
|
||||
self.isRestarting = ko.observable(false);
|
||||
self.isLoaded = ko.observable(false); // Becomes true after the first queue response
|
||||
self.useGlobalOptions = ko.observable(true).extend({ persist: 'useGlobalOptions' });
|
||||
self.refreshRate = ko.observable(1).extend({ persist: 'pageRefreshRate' });
|
||||
self.dateFormat = ko.observable('fromNow').extend({ persist: 'pageDateFormat' });
|
||||
@@ -424,7 +425,7 @@ function ViewModel() {
|
||||
self.openCustomPauseTime = function() {
|
||||
// Was it loaded already?
|
||||
if (!Date.i18n) {
|
||||
jQuery.getScript('./static/javascripts/date.min.js').then(function() {
|
||||
jQuery.getScript(dateScriptUrl).then(function() {
|
||||
// After loading we start again
|
||||
self.openCustomPauseTime()
|
||||
})
|
||||
@@ -701,7 +702,6 @@ function ViewModel() {
|
||||
data.append("priority", $('#modal-add-nzb select[name="Priority"]').val())
|
||||
data.append("pp", $('#modal-add-nzb select[name="Processing"]').val())
|
||||
data.append("script", $('#modal-add-nzb select[name="Post-processing"]').val())
|
||||
data.append("apikey", apiKey);
|
||||
|
||||
// Add this one
|
||||
$.ajax({
|
||||
@@ -1108,7 +1108,6 @@ function ViewModel() {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// Already set if we are using a proxy
|
||||
if (response.config.misc.socks5_proxy_url) self.statusInfo.active_socks5_proxy(true)
|
||||
|
||||
@@ -1165,6 +1164,9 @@ function ViewModel() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// First refresh has completed (success or failure): fade in the UI
|
||||
self.isLoaded(true);
|
||||
})
|
||||
|
||||
// Orphaned folder check - Not for 5 days if user ignored it
|
||||
@@ -1221,7 +1223,7 @@ function ViewModel() {
|
||||
}
|
||||
});
|
||||
$(document).bind('keydown', 'c', function(e) {
|
||||
window.location.href = './config/';
|
||||
window.location.href = './config';
|
||||
});
|
||||
$(document).bind('keydown', 's', function(e) {
|
||||
// Update the data
|
||||
@@ -1233,41 +1235,41 @@ function ViewModel() {
|
||||
});
|
||||
$(document).bind('keydown', 'shift+left', function(e) {
|
||||
if($("body").hasClass("container-tabbed")) {
|
||||
$('#history-tab.active > ul.pagination li.active').prev().click();
|
||||
$('#queue-tab.active > ul.pagination li.active').prev().click();
|
||||
$('#history-tab.active > ul.pagination li.active').prev().children('a').click();
|
||||
$('#queue-tab.active > ul.pagination li.active').prev().children('a').click();
|
||||
} else {
|
||||
$('#history-tab > ul.pagination li.active').prev().click();
|
||||
$('#queue-tab > ul.pagination li.active').prev().click();
|
||||
$('#history-tab > ul.pagination li.active').prev().children('a').click();
|
||||
$('#queue-tab > ul.pagination li.active').prev().children('a').click();
|
||||
}
|
||||
e.preventDefault();
|
||||
});
|
||||
$(document).bind('keydown', 'shift+right', function(e) {
|
||||
if($("body").hasClass("container-tabbed")) {
|
||||
$('#history-tab.active > ul.pagination li.active').next().click();
|
||||
$('#queue-tab.active > ul.pagination li.active').next().click();
|
||||
$('#history-tab.active > ul.pagination li.active').next().children('a').click();
|
||||
$('#queue-tab.active > ul.pagination li.active').next().children('a').click();
|
||||
} else {
|
||||
$('#history-tab > ul.pagination li.active').next().click();
|
||||
$('#queue-tab > ul.pagination li.active').next().click();
|
||||
$('#history-tab > ul.pagination li.active').next().children('a').click();
|
||||
$('#queue-tab > ul.pagination li.active').next().children('a').click();
|
||||
}
|
||||
e.preventDefault();
|
||||
});
|
||||
$(document).bind('keydown', 'shift+up', function(e) {
|
||||
if($("body").hasClass("container-tabbed")) {
|
||||
$('#history-tab.active > ul.pagination li').first().click();
|
||||
$('#queue-tab.active > ul.pagination li').first().click();
|
||||
$('#history-tab.active > ul.pagination li').first().children('a').click();
|
||||
$('#queue-tab.active > ul.pagination li').first().children('a').click();
|
||||
} else {
|
||||
$('#history-tab > ul.pagination li').first().click();
|
||||
$('#queue-tab > ul.pagination li').first().click();
|
||||
$('#history-tab > ul.pagination li').first().children('a').click();
|
||||
$('#queue-tab > ul.pagination li').first().children('a').click();
|
||||
}
|
||||
e.preventDefault();
|
||||
});
|
||||
$(document).bind('keydown', 'shift+down', function(e) {
|
||||
if($("body").hasClass("container-tabbed")) {
|
||||
$('#history-tab.active > ul.pagination li').last().click();
|
||||
$('#queue-tab.active > ul.pagination li').last().click();
|
||||
$('#history-tab.active > ul.pagination li').last().children('a').click();
|
||||
$('#queue-tab.active > ul.pagination li').last().children('a').click();
|
||||
} else {
|
||||
$('#history-tab > ul.pagination li').last().click();
|
||||
$('#queue-tab > ul.pagination li').last().click();
|
||||
$('#history-tab > ul.pagination li').last().children('a').click();
|
||||
$('#queue-tab > ul.pagination li').last().children('a').click();
|
||||
}
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
@@ -204,14 +204,14 @@ function QueueListModel(parent) {
|
||||
// Clear searchterm
|
||||
self.clearSearchTerm = function(data, event) {
|
||||
// Was it escape key or click?
|
||||
if(event.type === 'mousedown' || (event.keyCode && event.keyCode === 27)) {
|
||||
if(event.type === 'click' || (event.keyCode && event.keyCode === 27)) {
|
||||
self.isLoading(true)
|
||||
self.searchTerm('');
|
||||
}
|
||||
// Was it click and the field is empty? Then we focus on the field
|
||||
if(event.type === 'mousedown' && self.searchTerm() === '') {
|
||||
if(event.type === 'click' && self.searchTerm() === '') {
|
||||
$(event.target).parents('.search-box').find('input[type="text"]').focus()
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
// Need to return true to allow typing
|
||||
return true;
|
||||
@@ -228,6 +228,10 @@ function QueueListModel(parent) {
|
||||
sort = 'remaining';
|
||||
dir = 'asc';
|
||||
break;
|
||||
case 'sortRemainingBytesAsc':
|
||||
sort = 'remaining_bytes';
|
||||
dir = 'asc';
|
||||
break;
|
||||
case 'sortAgeAsc':
|
||||
sort = 'avg_age';
|
||||
dir = 'desc';
|
||||
@@ -549,7 +553,7 @@ function QueueModel(parent, data) {
|
||||
self.index = ko.observable(data.index);
|
||||
self.status = ko.observable(data.status);
|
||||
self.labels = ko.observableArray(data.labels);
|
||||
self.isGrabbing = ko.observable(data.status === 'Grabbing' || data.avg_age === '-')
|
||||
self.isGrabbing = ko.observable(data.status === 'Grabbing' || !parseFloat(data.mb)) // mb===0 catches paused URL-grab jobs (status 'Paused'), needed to block show-files
|
||||
self.isFetchingBlocks = data.status === 'Fetching' || data.priority === 'Repair' // No need to update
|
||||
self.totalMB = ko.observable(parseFloat(data.mb));
|
||||
self.remainingMB = ko.observable(parseFloat(data.mbleft))
|
||||
@@ -669,7 +673,7 @@ function QueueModel(parent, data) {
|
||||
self.password(data.password);
|
||||
self.index(data.index);
|
||||
self.status(data.status)
|
||||
self.isGrabbing(data.status === 'Grabbing' || data.avg_age === '-')
|
||||
self.isGrabbing(data.status === 'Grabbing' || !parseFloat(data.mb))
|
||||
self.totalMB(parseFloat(data.mb));
|
||||
self.remainingMB(parseFloat(data.mbleft));
|
||||
self.missingMB(parseFloat(data.mbmissing))
|
||||
@@ -782,39 +786,39 @@ function QueueModel(parent, data) {
|
||||
}
|
||||
|
||||
// Change of settings
|
||||
self.changeCat = function(item, event) {
|
||||
self.changeCat = function() {
|
||||
callAPI({
|
||||
mode: 'change_cat',
|
||||
value: item.id,
|
||||
value2: item.category()
|
||||
value: self.id,
|
||||
value2: self.category()
|
||||
}).then(function() {
|
||||
// Hide all tooltips before we refresh
|
||||
$('.queue-item-settings li').filter('[data-tooltip="true"]').tooltip('hide')
|
||||
self.parent.parent.refresh()
|
||||
})
|
||||
}
|
||||
self.changeScript = function(item) {
|
||||
self.changeScript = function() {
|
||||
callAPI({
|
||||
mode: 'change_script',
|
||||
value: item.id,
|
||||
value2: item.script()
|
||||
value: self.id,
|
||||
value2: self.script()
|
||||
})
|
||||
}
|
||||
self.changeProcessing = function(item) {
|
||||
self.changeProcessing = function() {
|
||||
callAPI({
|
||||
mode: 'change_opts',
|
||||
value: item.id,
|
||||
value2: item.unpackopts()
|
||||
value: self.id,
|
||||
value2: self.unpackopts()
|
||||
})
|
||||
}
|
||||
self.changePriority = function(item, event) {
|
||||
self.changePriority = function() {
|
||||
// Not if we are fetching extra blocks for repair!
|
||||
if(item.isFetchingBlocks) return
|
||||
if(self.isFetchingBlocks) return
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'priority',
|
||||
value: item.id,
|
||||
value2: item.priority()
|
||||
value: self.id,
|
||||
value2: self.priority()
|
||||
}).then(function() {
|
||||
// Hide all tooltips before we refresh
|
||||
$('.queue-item-settings li').filter('[data-tooltip="true"]').tooltip('hide')
|
||||
|
||||
File diff suppressed because one or more lines are too long.
File diff suppressed because one or more lines are too long.
@@ -1 +1 @@
|
||||
@import url('Night.css') screen and (prefers-color-scheme: dark);
|
||||
/* Placeholder — themes live in glitter.css; this file only populates the scheme dropdown */
|
||||
@@ -1,287 +1 @@
|
||||
body,
|
||||
.modal-backdrop {
|
||||
background-color: black;
|
||||
color: #EBEBEB
|
||||
}
|
||||
|
||||
nav {
|
||||
background-color: #444444 !important;
|
||||
border: 0 !important;
|
||||
border-bottom: 1px solid black !important;
|
||||
}
|
||||
|
||||
nav .btn {
|
||||
background-color: #E4E4E4;
|
||||
border-color: #5D5D5D !important;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
nav {
|
||||
background-color: black !important;
|
||||
}
|
||||
}
|
||||
|
||||
a, a:active, a:hover, a:focus,
|
||||
.hover-button.glyphicon-play,
|
||||
.hover-button.glyphicon-stop,
|
||||
.dropdown-menu>li>a,
|
||||
legend,
|
||||
#modal-options legend label,
|
||||
#modal-options legend a,
|
||||
#modal-item-files .item-files-table .progress small,
|
||||
#modal-options .options-switch label,
|
||||
#modal-options #options-orphans .process-all-orphaned,
|
||||
.text-muted {
|
||||
color: #EBEBEB;
|
||||
}
|
||||
|
||||
.dropdown-menu>li>a:hover,
|
||||
.dropdown-menu>li>a:focus,
|
||||
.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,
|
||||
.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,
|
||||
#feedback-slider {
|
||||
background-color: #555555;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.main-restarting,
|
||||
.main-filedrop,
|
||||
.nav-tabs>li>a {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.hover-button,
|
||||
.fileControls a:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.form-control[disabled] {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.progress {
|
||||
background-color: #DADADA;
|
||||
}
|
||||
|
||||
.main-notification-box {
|
||||
background-color: #727272;
|
||||
border-color: #252525 !important;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.main-notification-box-uploading-failed {
|
||||
color: #F95151;
|
||||
}
|
||||
|
||||
.container,
|
||||
.modal-body,
|
||||
.modal-footer {
|
||||
background-color: #727272;
|
||||
}
|
||||
|
||||
.dropdown-menu,
|
||||
.navbar-collapse.in .dropdown-menu {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
.navbar-collapse.in .dropdown-menu {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.max-speed-input-clear,
|
||||
.max-speed-input-clear:hover,
|
||||
.nav-tabs>li>a:hover,
|
||||
.fileControls a {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.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:focus {
|
||||
background-color: #ddd;
|
||||
color: #555 !important;
|
||||
box-shadow: 0px -1px 1px 1px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.processing-download > div {
|
||||
background-color: #EBEBEB;
|
||||
}
|
||||
|
||||
.table-striped>tbody>tr:nth-child(odd),
|
||||
.table>tbody>tr:nth-child(odd),
|
||||
.multioperations-selector,
|
||||
.pagination li.active span,
|
||||
.pagination li span:hover,
|
||||
.dropdown-menu .divider,
|
||||
.history-queue-swicher .badge {
|
||||
background-color: #444444;
|
||||
color: #EBEBEB;
|
||||
}
|
||||
|
||||
table,
|
||||
.table-striped>tbody>tr:nth-child(even),
|
||||
.table>tbody>tr:nth-child(even),
|
||||
.table th,
|
||||
.pagination li span,
|
||||
.pagination>.disabled>span,
|
||||
.pagination>.disabled>span:hover,
|
||||
.search-box input,
|
||||
input,
|
||||
input.form-control,
|
||||
.input-group-addon,
|
||||
select.form-control,
|
||||
.main-content .btn-default,
|
||||
.modal-body .btn-default,
|
||||
.modal-footer .btn-default,
|
||||
.btn-default.disabled:hover,
|
||||
.btn-default.disabled:active,
|
||||
.btn-default.disabled:focus,
|
||||
.form-control[disabled],
|
||||
#modal-options .options-function-box .input-group-addon {
|
||||
background-color: #555555;
|
||||
color: #EBEBEB;
|
||||
}
|
||||
|
||||
.btn-default:not(.navbar-btn):hover,
|
||||
select:hover,
|
||||
input:hover {
|
||||
background-color: #666666;
|
||||
}
|
||||
|
||||
/* Needed to force the text-color */
|
||||
.table-striped>tbody>tr:nth-child(odd)>td,
|
||||
.table>tbody>tr:nth-child(odd)>td,
|
||||
.table-striped>tbody>tr:nth-child(even)>td,
|
||||
.table>tbody>tr:nth-child(even)>td {
|
||||
color: #EBEBEB;
|
||||
}
|
||||
|
||||
/* Hovering the queue and the history */
|
||||
.table>tbody>tr:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
.table,
|
||||
tr td,
|
||||
tbody>tr>td:last-child,
|
||||
tbody>tr>td:first-child,
|
||||
tbody>tr:last-child td,
|
||||
.table-messages .table-messages-remove,
|
||||
.multioperations-selector,
|
||||
.pagination li span,
|
||||
.pagination li a,
|
||||
.search-box input,
|
||||
input,
|
||||
input.form-control,
|
||||
.input-group-addon,
|
||||
.search-box input:focus,
|
||||
.search-box input:valid,
|
||||
select.form-control,
|
||||
#modal-options .table-server-connections th,
|
||||
.main-content .btn-default,
|
||||
.modal-body .btn-default,
|
||||
.modal-footer .btn-default,
|
||||
.queue .table-active-sorting {
|
||||
border-color: #252525 !important;
|
||||
}
|
||||
|
||||
|
||||
.history-failed-download td.status,
|
||||
.retry-buttontext,
|
||||
.retry-button, .retry-button-inactive,
|
||||
.history-options-show-failed,
|
||||
.queue-error-info,
|
||||
.options-bad-status,
|
||||
.history-failed-download:hover .retry-button .glyphicon:before,
|
||||
.retry-button:hover .glyphicon:before {
|
||||
color: #F95151 !important;
|
||||
}
|
||||
|
||||
.ui-sortable-helper td {
|
||||
background-color: #555555 !important;
|
||||
}
|
||||
|
||||
tbody .caret {
|
||||
border-top-color: #EBEBEB !important;
|
||||
}
|
||||
|
||||
.info-container,
|
||||
#modal-options .options-status-box small,
|
||||
#modal-options #options-status small,
|
||||
#modal-options .tab-content h4,
|
||||
h2 small {
|
||||
color: #D6D6D6;
|
||||
}
|
||||
|
||||
td.name .name-icons span,
|
||||
.navbar-nav .open .dropdown-menu>li>a,
|
||||
.dropdown-header,
|
||||
#modal-help small,
|
||||
.hover-button.glyphicon-forward,
|
||||
pre {
|
||||
color: #EBEBEB !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
legend,
|
||||
hr {
|
||||
border-color: #C6C6C6 !important;
|
||||
}
|
||||
|
||||
.ui-slider .ui-slider-handle {
|
||||
background-color: #969696;
|
||||
border-color: #969696
|
||||
}
|
||||
|
||||
#modal-help table td,
|
||||
#modal-help table {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#modal-item-files .item-files-table td {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
#modal-item-files .item-files-table {
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
|
||||
.history-queue-swicher .nav-tabs>li>a,
|
||||
.history-queue-swicher .nav-tabs>li.active>a {
|
||||
border-bottom: none;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
.queue-item .dropdown-menu:after,
|
||||
.history-item .dropdown-menu:after,
|
||||
.info-container-box-sorting .dropdown-menu:after {
|
||||
border-bottom-color: #666;
|
||||
}
|
||||
|
||||
.container-compact .progress,
|
||||
.container-compact .queue .progress-bar {
|
||||
box-shadow: inset 1px 0px 1px rgba(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
border-color: #727272;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.form-control:focus,
|
||||
input[type="submit"]:focus,
|
||||
button:focus {
|
||||
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
|
||||
outline: initial;
|
||||
}
|
||||
|
||||
.archive-icon {
|
||||
fill: #EBEBEB;
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: #EBEBEB !important;
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
/* Placeholder — themes live in glitter.css; this file only populates the scheme dropdown */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -22,7 +22,8 @@
|
||||
|
||||
.main-content {
|
||||
border: 0;
|
||||
margin-bottom: 0 !important;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.main-menu-link .icon-bar:first-child {
|
||||
@@ -74,6 +75,10 @@ h2 {
|
||||
QUEUE & HISTORY
|
||||
**/
|
||||
|
||||
.history-queue-swicher {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.info-container {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 10px;
|
||||
@@ -95,13 +100,6 @@ h2 {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.info-container .info-container-box-sorting {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 0px;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.queue-table .table-header-progress {
|
||||
width: 0%;
|
||||
}
|
||||
@@ -128,7 +126,7 @@ h2 {
|
||||
}
|
||||
|
||||
.queue-table .progress {
|
||||
margin: 0px 8px;
|
||||
margin: 0px 15px;
|
||||
}
|
||||
|
||||
.queue-table td.name .row-wrap-text,
|
||||
@@ -151,6 +149,9 @@ tr.queue-item>td:first-child>a {
|
||||
|
||||
.queue-table td.name .name-options {
|
||||
display: inline-block;
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
position: static;
|
||||
}
|
||||
|
||||
.queue-table td.name .name-options small {
|
||||
@@ -274,4 +275,4 @@ tr.queue-item>td:first-child>a {
|
||||
#modal-item-files .form-group {
|
||||
clear: left;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="$active_lang">
|
||||
<html lang="$active_lang" data-color-scheme="$color_scheme">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>$T('wizard-quickstart')</title>
|
||||
<link rel="stylesheet" type="text/css" href="../staticcfg/bootstrap/css/bootstrap.min.css?v=$version"/>
|
||||
<link rel="stylesheet" type="text/css" href="static/style.css?v=$version"/>
|
||||
<!--#if $color_scheme not in ('Light', '') #-->
|
||||
<link rel="stylesheet" type="text/css" href="../staticcfg/css/${color_scheme}.css?v=$version"/>
|
||||
<!--#end if#-->
|
||||
<link rel="shortcut icon" href="../staticcfg/ico/favicon.ico?v=$version" />
|
||||
<script type="text/javascript" src="../staticcfg/js/jquery-3.5.1.min.js?v=$version"></script>
|
||||
<script type="text/javascript" src="../staticcfg/bootstrap/js/bootstrap.min.js?v=$version"></script>
|
||||
<link rel="stylesheet" type="text/css" href="$url('staticcfg/bootstrap/css/bootstrap.min.css', v=$cache_buster)"/>
|
||||
<link rel="stylesheet" type="text/css" href="$url('wizard/static/style.css', v=$cache_buster)"/>
|
||||
<link rel="shortcut icon" href="$url('staticcfg/ico/favicon.ico', v=$cache_buster)" />
|
||||
<script type="text/javascript" src="$url('staticcfg/js/jquery-3.7.1.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript" src="$url('staticcfg/bootstrap/js/bootstrap.min.js', v=$cache_buster)"></script>
|
||||
<script type="text/javascript">
|
||||
var csrfToken = "$csrf_token";
|
||||
$.ajaxSetup({
|
||||
headers: { "X-SABnzbd-CSRF": csrfToken }
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="logo">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<!--#include $webdir + "/inc_top.tmpl"#-->
|
||||
<form action="./one" method="post">
|
||||
<form action="$url('wizard/one')" method="post">
|
||||
<input type="hidden" name="csrf_token" value="$csrf_token" />
|
||||
<div class="container">
|
||||
<div id="inner">
|
||||
<div id="content" class="bigger">
|
||||
@@ -27,10 +28,10 @@
|
||||
<hr />
|
||||
<div class="row">
|
||||
<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>
|
||||
<button class="btn btn-danger" type="submit" form="shutdown-form"><span class="glyphicon glyphicon-remove"></span> $T('wizard-exit')</button>
|
||||
</div>
|
||||
<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>
|
||||
<a class="btn btn-default" href="$url('config/general#config_backup_file')"><span class="glyphicon glyphicon-open"></span> $T('restore-backup')</a>
|
||||
</div>
|
||||
<div class="col-md-4 text-center">
|
||||
<button class="btn btn-default">$T('wizard-start') <span class="glyphicon glyphicon-chevron-right"></span></button>
|
||||
@@ -39,4 +40,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<form id="shutdown-form" method="post" action="$url('shutdown')"><input type="hidden" name="csrf_token" value="$csrf_token" /></form>
|
||||
<!--#include $webdir + "/inc_bottom.tmpl"#-->
|
||||
@@ -1,5 +1,6 @@
|
||||
<!--#include $webdir + "/inc_top.tmpl"#-->
|
||||
<form action="./two" method="post" autocomplete="off">
|
||||
<form action="$url('wizard/two')" method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="$csrf_token" />
|
||||
<div class="container">
|
||||
<div id="inner">
|
||||
<div id="content" class="bigger">
|
||||
@@ -65,7 +66,7 @@
|
||||
<div class="form-group">
|
||||
<label for="connections" class="col-sm-4 control-label">$T('srv-connections')</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" class="form-control" name="connections" id="connections" value="<!--#if $connections then $connections else '8'#-->" min="1" max="500" data-toggle="tooltip" data-placement="right" title="$T('wizard-server-con-explain') $T('wizard-server-con-eg')" required />
|
||||
<input type="number" class="form-control" name="connections" id="connections" value="<!--#if $connections then $connections else '16'#-->" min="1" max="500" data-toggle="tooltip" data-placement="right" title="$T('wizard-server-con-explain') $T('wizard-server-con-eg')" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@@ -89,10 +90,10 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<button id="serverTest" class="btn btn-default" data-toggle="tooltip" data-placement="left"><span class="glyphicon glyphicon-sort"></span> $T('wizard-button-testServer')</button>
|
||||
<button id="serverTest" class="btn btn-default" data-toggle="tooltip" data-placement="left" aria-busy="false"><span class="glyphicon glyphicon-sort" aria-hidden="true"></span> $T('wizard-button-testServer')</button>
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<div id="serverResponse" class="well well-sm">$T('wizard-server-text')</div>
|
||||
<div id="serverResponse" class="well well-sm" role="status" aria-live="polite" aria-atomic="true">$T('wizard-server-text')</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -102,12 +103,12 @@
|
||||
<iframe style="float: right; width: 325px; height: 325px;" frameborder="0" src="https://sabnzbd.org/wizard#$active_lang"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="apikey" value="$apikey" />
|
||||
<input type="hidden" name="enable" value="1">
|
||||
</div>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-xs-4 text-center">
|
||||
<a class="btn btn-default" href="./index"><span class="glyphicon glyphicon-chevron-left"></span> $T('wizard-previous')</a>
|
||||
<a class="btn btn-default" href="$url('wizard')"><span class="glyphicon glyphicon-chevron-left"></span> $T('wizard-previous')</a>
|
||||
</div>
|
||||
<div class="col-xs-4 text-center">
|
||||
</div>
|
||||
|
||||
@@ -41,22 +41,25 @@ $(document).ready(function() {
|
||||
return false;
|
||||
}
|
||||
|
||||
$('#serverTest').attr('aria-busy', 'true');
|
||||
$('#serverResponse').html(txtChecking);
|
||||
$.getJSON(
|
||||
"../api?mode=config&name=test_server&output=json",
|
||||
$("form").serialize(),
|
||||
function(result) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: "../api?mode=config&name=test_server&output=json",
|
||||
data: $("form").serialize(),
|
||||
success: function(result) {
|
||||
if (result.value.result) {
|
||||
r = '<span class="success"><span class="glyphicon glyphicon-ok"></span> ' + result.value.message + '</span>';
|
||||
r = '<span class="success"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span> ' + result.value.message + '</span>';
|
||||
setTestResult(true);
|
||||
} else {
|
||||
r = '<span class="failed"><span class="glyphicon glyphicon-minus-sign"></span> ' + result.value.message + '</span>';
|
||||
r = '<span class="failed"><span class="glyphicon glyphicon-minus-sign" aria-hidden="true"></span> ' + result.value.message + '</span>';
|
||||
setTestResult(false);
|
||||
}
|
||||
r = r.replace('https://sabnzbd.org/certificate-errors', '<a href="https://sabnzbd.org/certificate-errors" class="failed" target="_blank">https://sabnzbd.org/certificate-errors</a>')
|
||||
$('#serverResponse').html(r);
|
||||
$('#serverTest').attr('aria-busy', 'false');
|
||||
}
|
||||
);
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -88,4 +91,4 @@ $(document).ready(function() {
|
||||
event.preventDefault();
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
@@ -1,16 +1,50 @@
|
||||
:root {
|
||||
/* Border radius scale */
|
||||
--radius-sm: 4px; /* small elements: progress bars */
|
||||
--radius-md: 6px; /* search bar, multi-edit toolbar, file controls */
|
||||
--radius-lg: 8px; /* cards, modals, notification box */
|
||||
|
||||
/* Follow the OS by default (Auto); forced by data-color-scheme below */
|
||||
color-scheme: light dark;
|
||||
|
||||
/* Color palette — light-dark(light value, dark value) */
|
||||
--clr-page-bg: light-dark(#E4E4E4, black);
|
||||
--clr-surface: light-dark(#FFFFFF, #303030);
|
||||
--clr-surface-alt: light-dark(#F5F5F5, #444444);
|
||||
--clr-surface-hover: light-dark(#E4E4E4, #666666);
|
||||
--clr-border: light-dark(rgba(0, 0, 0, 0.2), #555555);
|
||||
--clr-text: light-dark(#000000, #EBEBEB);
|
||||
--clr-text-muted: light-dark(#777777, #c7c7c7);
|
||||
--clr-link: light-dark(#555555, #63a7e1);
|
||||
--clr-input-bg: light-dark(#FFFFFF, #555555);
|
||||
--clr-input-border: light-dark(#cccccc, #252525);
|
||||
--clr-toggle-active: #f9ca33;
|
||||
--clr-toggle-inactive: light-dark(#aaaaaa, #666666);
|
||||
}
|
||||
|
||||
/* The server renders the configured scheme into this attribute; empty/unknown = Auto */
|
||||
html[data-color-scheme="light" i] {
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
html[data-color-scheme="night" i] {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #E4E4E4;
|
||||
background-color: var(--clr-page-bg);
|
||||
color: var(--clr-text);
|
||||
text-align: center;
|
||||
}
|
||||
.container {
|
||||
max-width: 1000px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
background-color: #fff;
|
||||
text-align: left;
|
||||
}
|
||||
#inner {
|
||||
background-color: #fff;
|
||||
padding: 4px 32px 20px 32px;
|
||||
border: 1px solid var(--clr-border);
|
||||
border-radius: var(--radius-lg);
|
||||
background-color: var(--clr-surface);
|
||||
}
|
||||
#content {
|
||||
min-height: 550px;
|
||||
@@ -33,7 +67,7 @@ body {
|
||||
float: left;
|
||||
}
|
||||
.language:hover {
|
||||
background-color: #E4E4E4;
|
||||
background-color: var(--clr-surface-hover);
|
||||
}
|
||||
.float {
|
||||
float: left;
|
||||
@@ -51,7 +85,7 @@ body {
|
||||
padding: 12px;
|
||||
margin-top: 1px;
|
||||
margin-bottom: 15px;
|
||||
background-color: #f5f5f5;
|
||||
background-color: var(--clr-surface-alt);
|
||||
}
|
||||
.quoteBlock a,
|
||||
a[target="_blank"] {
|
||||
@@ -62,10 +96,10 @@ a[target="_blank"] {
|
||||
color: #00cc22;
|
||||
}
|
||||
.failed {
|
||||
color: red !important;
|
||||
color: light-dark(red, #ff3333) !important;
|
||||
}
|
||||
#rightGreyText {
|
||||
color: #ccc;
|
||||
color: light-dark(#cccccc, #c7c7c7);
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
padding-top: 3px;
|
||||
@@ -80,6 +114,39 @@ label {
|
||||
.input-checkbox {
|
||||
padding-top: 7px !important;
|
||||
}
|
||||
/* Toggle switch */
|
||||
input[type="checkbox"] {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
width: 36px;
|
||||
height: 20px;
|
||||
background-color: var(--clr-toggle-inactive);
|
||||
background-image:
|
||||
radial-gradient(circle at 10px 10px, #ffffff 6.5px, rgba(255,255,255,0) 7px),
|
||||
radial-gradient(circle at 11px 11px, rgba(0,0,0,0.30) 6.5px, transparent 9.5px);
|
||||
background-size: 20px 20px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0px center;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, background-position 0.15s;
|
||||
}
|
||||
input[type="checkbox"]:checked {
|
||||
background-color: var(--clr-toggle-active);
|
||||
background-position: 16px center;
|
||||
background-image:
|
||||
radial-gradient(circle at 10px 10px, #ffffff 6.5px, rgba(255,255,255,0) 7px),
|
||||
radial-gradient(circle at 10.5px 10.5px, rgba(0,0,0,0.30) 6.5px, transparent 9.5px);
|
||||
}
|
||||
input[type="checkbox"]:focus-visible {
|
||||
outline: 2px solid var(--clr-toggle-active);
|
||||
outline-offset: 2px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.input-checkbox input+.help-block {
|
||||
display: none;
|
||||
}
|
||||
@@ -136,24 +203,110 @@ label {
|
||||
Bootstrap overwrites
|
||||
***/
|
||||
|
||||
* {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
a,
|
||||
a:hover,
|
||||
a:active,
|
||||
a:visited,
|
||||
#serverResponse {
|
||||
color: #555;
|
||||
color: var(--clr-link);
|
||||
}
|
||||
.btn {
|
||||
box-shadow: 1px 1px 1px rgba(0, 0, 0, .1) !important;
|
||||
min-width: 150px;
|
||||
box-shadow: 1px 0px 1px light-dark(rgba(0,0,0,.1), rgba(255,255,255,.1));
|
||||
}
|
||||
|
||||
.btn-default,
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="email"],
|
||||
input[type="password"],
|
||||
input[type="url"],
|
||||
select,
|
||||
textarea {
|
||||
background-color: var(--clr-input-bg);
|
||||
color: var(--clr-text);
|
||||
border-color: var(--clr-input-border);
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: var(--clr-text) !important;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.btn .glyphicon,
|
||||
a .glyphicon {
|
||||
top: 2px;
|
||||
}
|
||||
small {
|
||||
color: #777;
|
||||
color: var(--clr-text-muted);
|
||||
}
|
||||
|
||||
/***
|
||||
Dark-mode structural rules
|
||||
Colors live in the light-dark() tokens above; these are the rules that cannot
|
||||
be expressed as a color value. The two blocks below MUST stay identical:
|
||||
the first applies when Night is forced, the second when the OS is dark and Light is not forced.
|
||||
***/
|
||||
html[data-color-scheme="night" i] {
|
||||
.language:hover,
|
||||
.quoteBlock,
|
||||
.server-disabled,
|
||||
#serverResponse {
|
||||
background-color: var(--clr-surface-alt) !important;
|
||||
color: var(--clr-text) !important;
|
||||
}
|
||||
|
||||
.quoteBlock a,
|
||||
.help-block,
|
||||
a.wizard-advanced-settings {
|
||||
color: var(--clr-text);
|
||||
}
|
||||
|
||||
#inner {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Focus / active border */
|
||||
.btn-default:focus,
|
||||
.form-control:focus,
|
||||
input:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
border-color: #707070 !important;
|
||||
outline: initial !important;
|
||||
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html:not([data-color-scheme="light" i]) {
|
||||
.language:hover,
|
||||
.quoteBlock,
|
||||
.server-disabled,
|
||||
#serverResponse {
|
||||
background-color: var(--clr-surface-alt) !important;
|
||||
color: var(--clr-text) !important;
|
||||
}
|
||||
|
||||
.quoteBlock a,
|
||||
.help-block,
|
||||
a.wizard-advanced-settings {
|
||||
color: var(--clr-text);
|
||||
}
|
||||
|
||||
#inner {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Focus / active border */
|
||||
.btn-default:focus,
|
||||
.form-control:focus,
|
||||
input:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
border-color: #707070 !important;
|
||||
outline: initial !important;
|
||||
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@
|
||||
<p>$T('wizard-tip4')</p>
|
||||
|
||||
<div class="quoteBlock">
|
||||
<!--#for $url in $urls#-->
|
||||
<a href="$url">$url</a><br />
|
||||
<!--#for $access_url in $urls#-->
|
||||
<a href="$access_url">$access_url</a><br />
|
||||
<!--#end for#-->
|
||||
</div>
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
<p><strong>$T('opt-complete_dir')</strong></p>
|
||||
<div class="quoteBlock">
|
||||
$complete_dir
|
||||
<a href="${access_url}/config/folders#complete_dir" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
|
||||
<a href="$url('config/folders#complete_dir')" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
|
||||
</div>
|
||||
|
||||
<p><strong>$T('opt-download_dir')</strong></p>
|
||||
<div class="quoteBlock">
|
||||
$download_dir
|
||||
<a href="${access_url}/config/folders#complete_dir" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
|
||||
<a href="$url('config/folders#complete_dir')" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
@@ -38,8 +38,7 @@
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-xs-12 text-center">
|
||||
<input type="hidden" name="apikey" id="apikey" value="$apikey"/>
|
||||
<a class="btn btn-success" href="$access_url">$T('wizard-goto') <span class="glyphicon glyphicon-chevron-right"></span></a>
|
||||
<a class="btn btn-success" href="$url()">$T('wizard-goto') <span class="glyphicon glyphicon-chevron-right"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
<metadata_license>MIT</metadata_license>
|
||||
<name>SABnzbd</name>
|
||||
<summary>Free and easy binary newsreader</summary>
|
||||
<summary xml:lang="fr">Lecteur de news binaire libre et facile à utiliser</summary>
|
||||
<summary xml:lang="tr">Özgür ve kullanımı kolay Usenet ikili okuyucu</summary>
|
||||
<branding>
|
||||
<color type="primary" scheme_preference="light">#e7e7e7</color>
|
||||
<color type="primary" scheme_preference="dark">#444444</color>
|
||||
@@ -20,6 +22,26 @@
|
||||
over a dozen languages, and integrates with a host of tools, apps
|
||||
and services that help automate the download process.
|
||||
</p>
|
||||
<p xml:lang="fr">
|
||||
SABnzbd est un lecteur binaire de newsgroups libre et gratuit prenant
|
||||
en charge le format nzb très répandu. Il simplifie grandement le processus
|
||||
de téléchargement depuis Usenet grâce à une interface web conviviale
|
||||
et à des options avancées de post-traitement intégrées qui comprennent
|
||||
la capacité à vérifier, réparer, extraire et nettoyer automatiquement
|
||||
les messages téléchargés. Il fonctionne partout, est fourni avec une
|
||||
douzaine de traductions et s'intègre avec de nombreux outils, applications
|
||||
et services qui aident à automatiser le processus de téléchargement.
|
||||
</p>
|
||||
<p xml:lang="tr">
|
||||
SABnzbd, popüler nzb biçimini destekleyen özgür ve ücretsiz bir ikili
|
||||
haber grupları okuyucusudur. Kullanıcı dostu Web tabanlı arayüzü ve
|
||||
indirilen mesajları otomatik olarak doğrulama, tamir etme, çıkarma ve
|
||||
temizleme kabiliyetine sahip gelişmiş yerleşik son işlem seçenekleri
|
||||
sayesinde Usenet ağından indirmeyi büyük ölçüde kolaylaştırır. Her yerde
|
||||
çalışabilir, bir düzineden fazla dil desteği sunar ve indirme sürecini
|
||||
otomatik hâle getirmeye yardımcı olan birçok araç, uygulama ve hizmet ile
|
||||
birlikte çalışabilir.
|
||||
</p>
|
||||
</description>
|
||||
<keywords>
|
||||
<keyword>usenet</keyword>
|
||||
@@ -27,6 +49,13 @@
|
||||
<keyword>download</keyword>
|
||||
<keyword>newsreader</keyword>
|
||||
<keyword>binary</keyword>
|
||||
<keyword xml:lang="fr">usenet</keyword>
|
||||
<keyword xml:lang="fr">nzb</keyword>
|
||||
<keyword xml:lang="fr">téléchargement</keyword>
|
||||
<keyword xml:lang="fr">binaires</keyword>
|
||||
<keyword xml:lang="tr">usenet</keyword>
|
||||
<keyword xml:lang="tr">nzb</keyword>
|
||||
<keyword xml:lang="tr">indirme</keyword>
|
||||
</keywords>
|
||||
<categories>
|
||||
<category>Network</category>
|
||||
@@ -42,6 +71,21 @@
|
||||
<url type="faq">https://sabnzbd.org/wiki/faq</url>
|
||||
<url type="contact">https://sabnzbd.org/live-chat.html</url>
|
||||
<releases>
|
||||
<release version="5.1.0" date="2026-08-01" type="stable">
|
||||
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/5.1.0</url>
|
||||
</release>
|
||||
<release version="5.0.4" date="2026-06-11" type="stable">
|
||||
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/5.0.4</url>
|
||||
</release>
|
||||
<release version="5.0.3" date="2026-05-15" type="stable">
|
||||
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/5.0.3</url>
|
||||
</release>
|
||||
<release version="5.0.2" date="2026-05-14" type="stable">
|
||||
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/5.0.2</url>
|
||||
</release>
|
||||
<release version="5.0.1" date="2026-05-01" type="stable">
|
||||
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/5.0.1</url>
|
||||
</release>
|
||||
<release version="5.0.0" date="2026-05-01" type="stable">
|
||||
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/5.0.0</url>
|
||||
</release>
|
||||
@@ -101,62 +145,92 @@
|
||||
<screenshot type="default">
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/interface.png</image>
|
||||
<caption>Intuitive interface</caption>
|
||||
<caption xml:lang="fr">Interface intuitive</caption>
|
||||
<caption xml:lang="tr">Sezgisel arayüz</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/night-mode.png</image>
|
||||
<caption>Also comes in Night-mode</caption>
|
||||
<caption xml:lang="fr">Fourni également avec le mode nuit</caption>
|
||||
<caption xml:lang="tr">Gece kipi ile de sunulur</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/add-nzb.png</image>
|
||||
<caption>Add NZB's or use drag-and-drop!</caption>
|
||||
<caption xml:lang="fr">Ajoutez des fichiers NZB ou utilisez le glisser - déposer !</caption>
|
||||
<caption xml:lang="tr">NZB dosyaları ekleyin veya kaydır - bırak kullanın!</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/phone-interface.png</image>
|
||||
<caption>Scales to any screen size</caption>
|
||||
<caption xml:lang="fr">S'adapte à toutes les tailles d'écran</caption>
|
||||
<caption xml:lang="tr">Her ekran boyutuna uyum sağlar</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/history-details.png</image>
|
||||
<caption>Easy overview of all history details</caption>
|
||||
<caption xml:lang="fr">Vue d'ensemble aisée de tous les détails de l'historique</caption>
|
||||
<caption xml:lang="tr">Tarihçenin tüm ayrıntıları için kolay genel bakış</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/phone-extra.png</image>
|
||||
<caption>Every option, on every screen size</caption>
|
||||
<caption xml:lang="fr">Toutes les options, quelle que soit la taille d'écran</caption>
|
||||
<caption xml:lang="tr">Ekran boyutu ne olursa olsun, tüm seçenekler elinizin altında</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/file-lists.png</image>
|
||||
<caption>Manage a job's individual files</caption>
|
||||
<caption xml:lang="fr">Gérez les fichiers individuels d'une tâche</caption>
|
||||
<caption xml:lang="tr">Herhangi bir görevin dosyalarını tek tek yönetin</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/set-speedlimit.png</image>
|
||||
<caption>Easy speed limiting</caption>
|
||||
<caption xml:lang="fr">Limitation facile du débit</caption>
|
||||
<caption xml:lang="tr">Kolay hız sınırlaması</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/set-options.png</image>
|
||||
<caption>Quickly change settings</caption>
|
||||
<caption xml:lang="fr">Changement rapide des réglages</caption>
|
||||
<caption xml:lang="tr">Ayarları hızlıca değiştirin</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/dashboard.png</image>
|
||||
<caption>Easy system check</caption>
|
||||
<caption xml:lang="fr">Vérification facile du système</caption>
|
||||
<caption xml:lang="tr">Sistemi kolayca kontrol edin</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/connections-overview.png</image>
|
||||
<caption>See active connections</caption>
|
||||
<caption xml:lang="fr">Voyez les connexions actives</caption>
|
||||
<caption xml:lang="tr">Etkin bağlantıları görüntüleyin</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/skin-settings.png</image>
|
||||
<caption>Customize the interface</caption>
|
||||
<caption xml:lang="fr">Personnalisez l'interface</caption>
|
||||
<caption xml:lang="tr">Arayüzü kişiselleştirin</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/tabbed.png</image>
|
||||
<caption>Tabbed-mode</caption>
|
||||
<caption xml:lang="fr">Mode avec onglets</caption>
|
||||
<caption xml:lang="tr">Sekmeli kip</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/set-custom-pause.png</image>
|
||||
<caption>Specify any pause duration</caption>
|
||||
<caption xml:lang="fr">Spécifiez une durée de pause quelconque</caption>
|
||||
<caption xml:lang="tr">Herhangi bir duraklama süresi belirtin</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://sabnzbd.org/images/landing/screenshots/config.png</image>
|
||||
<caption>Easy configuration</caption>
|
||||
<caption xml:lang="fr">Configuration facile</caption>
|
||||
<caption xml:lang="tr">Kolay yapılandırma</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<content_rating type="oars-1.1"/>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: team@sabnzbd.org\n"
|
||||
"Language-Team: SABnzbd <team@sabnzbd.org>\n"
|
||||
|
||||
+93
-1
@@ -1,10 +1,14 @@
|
||||
# SABnzbd Translation Template file EMAIL
|
||||
# Copyright 2007-2026 by The SABnzbd-Team (sabnzbd.org)
|
||||
#
|
||||
# Translators:
|
||||
# Iamanro, 2026
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Iamanro, 2026\n"
|
||||
"Language-Team: Czech (https://app.transifex.com/sabnzbd/teams/111101/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -56,6 +60,47 @@ msgid ""
|
||||
"Sorry!\n"
|
||||
"<!--#end if#-->\n"
|
||||
msgstr ""
|
||||
"##\n"
|
||||
"## Výchozí e-mailová šablona pro SABnzbd\n"
|
||||
"## Toto je šablona Cheetah\n"
|
||||
"## Dokumentace: https://sabnzbd.org/wiki/extra/email-templates\n"
|
||||
"##\n"
|
||||
"## Nové řádky a mezery jsou významné!\n"
|
||||
"##\n"
|
||||
"## Toto jsou hlavičky e-mailu\n"
|
||||
"To: $to\n"
|
||||
"From: $from\n"
|
||||
"Date: $date\n"
|
||||
"Subject: SABnzbd <!--#if $status then \"dokončil\" else \"nedokončil\" #--> úlohu $name\n"
|
||||
"X-priority: 5\n"
|
||||
"X-MS-priority: 5\n"
|
||||
"## Poté následuje tělo zprávy, prázdný řádek je povinný!\n"
|
||||
"\n"
|
||||
"Dobrý den,\n"
|
||||
"<!--#if $status #-->\n"
|
||||
"SABnzbd stáhl \"$name\" <!--#if $msgid==\"\" then \"\" else \"(newzbin #\" + $msgid + \")\"#-->\n"
|
||||
"<!--#else#-->\n"
|
||||
"SABnzbd nedokázal stáhnout \"$name\" <!--#if $msgid==\"\" then \"\" else \"(newzbin #\" + $msgid + \")\"#-->\n"
|
||||
"<!--#end if#-->\n"
|
||||
"Dokončeno v $end_time\n"
|
||||
"Staženo $size\n"
|
||||
"\n"
|
||||
"Výsledky úlohy:\n"
|
||||
"<!--#for $stage in $stages #-->\n"
|
||||
"Fáze $stage <!--#slurp#-->\n"
|
||||
"<!--#for $result in $stages[$stage]#-->\n"
|
||||
"$result <!--#slurp#-->\n"
|
||||
"<!--#end for#-->\n"
|
||||
"<!--#end for#-->\n"
|
||||
"<!--#if $script!=\"\" #-->\n"
|
||||
"Výstup z uživatelského skriptu \"$script\" (Návratový kód = $script_ret):\n"
|
||||
"$script_output\n"
|
||||
"<!--#end if#-->\n"
|
||||
"<!--#if $status #-->\n"
|
||||
"Užijte si to!\n"
|
||||
"<!--#else#-->\n"
|
||||
"Je nám líto!\n"
|
||||
"<!--#end if#-->\n"
|
||||
|
||||
#: email/rss.tmpl:1
|
||||
msgid ""
|
||||
@@ -85,6 +130,31 @@ msgid ""
|
||||
"\n"
|
||||
"Bye\n"
|
||||
msgstr ""
|
||||
"##\n"
|
||||
"## E-mailová šablona RSS pro SABnzbd\n"
|
||||
"## Toto je šablona Cheetah\n"
|
||||
"## Dokumentace: https://sabnzbd.org/wiki/extra/email-templates\n"
|
||||
"##\n"
|
||||
"## Nové řádky a mezery jsou významné!\n"
|
||||
"##\n"
|
||||
"## Toto jsou hlavičky e-mailu\n"
|
||||
"To: $to\n"
|
||||
"From: $from\n"
|
||||
"Date: $date\n"
|
||||
"Subject: SABnzbd přidal $amount úloh do fronty\n"
|
||||
"X-priority: 5\n"
|
||||
"X-MS-priority: 5\n"
|
||||
"## Poté následuje tělo zprávy, prázdný řádek je povinný!\n"
|
||||
"\n"
|
||||
"Dobrý den,\n"
|
||||
"\n"
|
||||
"SABnzbd přidal $amount úloh do fronty.\n"
|
||||
"Pocházejí z RSS kanálu \"$feed\".\n"
|
||||
"<!--#for $job in $jobs#-->\n"
|
||||
"$job <!--#slurp#-->\n"
|
||||
"<!--#end for#-->\n"
|
||||
"\n"
|
||||
"Na shledanou\n"
|
||||
|
||||
#: email/badfetch.tmpl:1
|
||||
msgid ""
|
||||
@@ -111,3 +181,25 @@ msgid ""
|
||||
"\n"
|
||||
"Bye\n"
|
||||
msgstr ""
|
||||
"##\n"
|
||||
"## E-mailová šablona SABnzbd pro neúspěšné načtení URL\n"
|
||||
"## Toto je šablona Cheetah\n"
|
||||
"## Dokumentace: https://sabnzbd.org/wiki/extra/email-templates\n"
|
||||
"##\n"
|
||||
"## Nové řádky a mezery jsou významné!\n"
|
||||
"##\n"
|
||||
"## Toto jsou hlavičky e-mailu\n"
|
||||
"To: $to\n"
|
||||
"From: $from\n"
|
||||
"Date: $date\n"
|
||||
"Subject: SABnzbd nedokázal získat NZB\n"
|
||||
"X-priority: 5\n"
|
||||
"X-MS-priority: 5\n"
|
||||
"## Poté následuje tělo zprávy, prázdný řádek je povinný!\n"
|
||||
"\n"
|
||||
"Dobrý den,\n"
|
||||
"\n"
|
||||
"SABnzbd nedokázal získat NZB z $url.\n"
|
||||
"Chybová zpráva byla: $msg\n"
|
||||
"\n"
|
||||
"Na shledanou\n"
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Language-Team: Danish (https://app.transifex.com/sabnzbd/teams/111101/da/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
|
||||
"Language-Team: German (https://app.transifex.com/sabnzbd/teams/111101/de/)\n"
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Language-Team: Spanish (https://app.transifex.com/sabnzbd/teams/111101/es/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Language-Team: Finnish (https://app.transifex.com/sabnzbd/teams/111101/fi/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Fred L <88com88@gmail.com>, 2025\n"
|
||||
"Language-Team: French (https://app.transifex.com/sabnzbd/teams/111101/fr/)\n"
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
|
||||
"Language-Team: Hebrew (https://app.transifex.com/sabnzbd/teams/111101/he/)\n"
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Language-Team: Italian (https://app.transifex.com/sabnzbd/teams/111101/it/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Language-Team: Norwegian Bokmål (https://app.transifex.com/sabnzbd/teams/111101/nb/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
|
||||
"Language-Team: Dutch (https://app.transifex.com/sabnzbd/teams/111101/nl/)\n"
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Language-Team: Polish (https://app.transifex.com/sabnzbd/teams/111101/pl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Language-Team: Portuguese (Brazil) (https://app.transifex.com/sabnzbd/teams/111101/pt_BR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Language-Team: Romanian (https://app.transifex.com/sabnzbd/teams/111101/ro/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Language-Team: Russian (https://app.transifex.com/sabnzbd/teams/111101/ru/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Language-Team: Serbian (https://app.transifex.com/sabnzbd/teams/111101/sr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Language-Team: Swedish (https://app.transifex.com/sabnzbd/teams/111101/sv/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Last-Translator: mauron, 2025\n"
|
||||
"Language-Team: Turkish (https://app.transifex.com/sabnzbd/teams/111101/tr/)\n"
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
|
||||
"Language-Team: Chinese (China) (https://app.transifex.com/sabnzbd/teams/111101/zh_CN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+155
-110
@@ -4,7 +4,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: team@sabnzbd.org\n"
|
||||
"Language-Team: SABnzbd <team@sabnzbd.org>\n"
|
||||
@@ -105,7 +105,6 @@ msgstr ""
|
||||
msgid "SABnzbd shutdown finished"
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/__init__.py
|
||||
msgid "Signal %s caught, saving and exiting..."
|
||||
msgstr ""
|
||||
@@ -207,6 +206,10 @@ msgstr ""
|
||||
msgid "Unknown SSL protocol: Try disabling SSL or connecting on a different port."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Could not determine connection result (%s)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Server requires username and password."
|
||||
msgstr ""
|
||||
@@ -215,16 +218,9 @@ msgstr ""
|
||||
msgid "Connection Successful!"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/api.py, sabnzbd/interface.py
|
||||
msgid "Authentication failed, check username/password."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/api.py
|
||||
msgid "Too many connections, please pause downloading or try again later"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Could not determine connection result (%s)"
|
||||
msgid "Server %s took %d ms to respond. On high-latency connections, increasing 'Articles per request' to a value between 5 and 10 can improve download speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/api.py
|
||||
@@ -242,12 +238,12 @@ msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/assembler.py
|
||||
#: sabnzbd/assembler.py, sabnzbd/decoder.py
|
||||
msgid "Disk full! Forcing Pause"
|
||||
msgstr ""
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/assembler.py
|
||||
#: sabnzbd/assembler.py, sabnzbd/decoder.py
|
||||
msgid "Disk error on creating file %s"
|
||||
msgstr ""
|
||||
|
||||
@@ -476,7 +472,7 @@ msgid "Resuming"
|
||||
msgstr ""
|
||||
|
||||
#. PP status - Priority pick list
|
||||
#: sabnzbd/downloader.py, sabnzbd/macosmenu.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/downloader.py, sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
@@ -514,15 +510,7 @@ msgid "Fatal error in Downloader"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/downloader.py
|
||||
msgid "Too many connections to server %s [%s]"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/downloader.py
|
||||
msgid "Login from too many different IP addresses to server %s [%s] - https://sabnzbd.org/multiple-adresses"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/downloader.py
|
||||
msgid "Failed login for server %s [%s]"
|
||||
msgid "Server %s reported: %s"
|
||||
msgstr ""
|
||||
|
||||
#. Error message
|
||||
@@ -530,6 +518,11 @@ msgstr ""
|
||||
msgid "Connecting %s@%s failed, message=%s"
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/downloader.py
|
||||
msgid "Total number of configured connections (%d) is greater than the operating system limit (512), downloading will crash if all connections become active"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/downloader.py, sabnzbd/skintext.py
|
||||
msgid "Shutting down"
|
||||
msgstr ""
|
||||
@@ -681,11 +674,16 @@ msgid "Direct Write mode has been disabled because %s does not support sparse fi
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Refused connection from:"
|
||||
msgid "Refused connection with hostname \"%s\" from:"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Refused connection with hostname \"%s\" from:"
|
||||
msgid "API Key incorrect, Use the api key from Config->General in your 3rd party program:"
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/interface.py, sabnzbd/security.py
|
||||
msgid "Refused connection from:"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
@@ -693,16 +691,16 @@ msgid "API Key missing, please enter the api key from Config->General into your
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "API Key incorrect, Use the api key from Config->General in your 3rd party program:"
|
||||
msgid "Too many failed login attempts, try again later."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Login attempt refused, too many failures from %s"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "User logged in to the web interface"
|
||||
msgstr ""
|
||||
|
||||
#. Notification
|
||||
#: sabnzbd/interface.py, sabnzbd/notifier.py
|
||||
msgid "User logged in"
|
||||
msgid "Authentication failed, check username/password."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
@@ -763,14 +761,6 @@ msgstr ""
|
||||
msgid "Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py, sabnzbd/skintext.py
|
||||
msgid "ERROR:"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/internetspeed.py
|
||||
msgid "Internet Bandwidth of IPv4 significantly different from IPv6: %f MB/s versus %f MB/s"
|
||||
@@ -781,7 +771,7 @@ msgstr ""
|
||||
msgid "Warnings"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Idle"
|
||||
msgstr ""
|
||||
|
||||
@@ -810,7 +800,7 @@ msgid "Limit Speed"
|
||||
msgstr ""
|
||||
|
||||
#. Notification - Pause downloading - Four way switch for duplicates - Config->Scheduling
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause"
|
||||
msgstr ""
|
||||
|
||||
@@ -820,7 +810,7 @@ msgid "min"
|
||||
msgstr ""
|
||||
|
||||
#. Notification - Resume downloading - Config->Scheduling
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Resume"
|
||||
msgstr ""
|
||||
|
||||
@@ -829,7 +819,7 @@ msgstr ""
|
||||
msgid "Scan watched folder"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Read all RSS feeds"
|
||||
msgstr ""
|
||||
|
||||
@@ -841,16 +831,16 @@ msgstr ""
|
||||
msgid "Incomplete Folder"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraywin.py
|
||||
msgid "Troubleshoot"
|
||||
msgstr ""
|
||||
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Restart"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraywin.py
|
||||
msgid "Restart without login"
|
||||
msgstr ""
|
||||
|
||||
@@ -1040,6 +1030,10 @@ msgstr ""
|
||||
msgid "see logfile"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/newsunpack.py
|
||||
msgid "Unpacking skipped, TAR support requires Python 3.12 or later"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/newsunpack.py
|
||||
msgid "Quick Checking"
|
||||
msgstr ""
|
||||
@@ -1196,6 +1190,11 @@ msgstr ""
|
||||
msgid "Queue finished"
|
||||
msgstr ""
|
||||
|
||||
#. Notification
|
||||
#: sabnzbd/notifier.py
|
||||
msgid "User logged in"
|
||||
msgstr ""
|
||||
|
||||
#. Notification
|
||||
#: sabnzbd/notifier.py
|
||||
msgid "Other Messages"
|
||||
@@ -1207,7 +1206,7 @@ msgid "Open folder"
|
||||
msgstr ""
|
||||
|
||||
#. Notification action
|
||||
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
#: sabnzbd/notifier.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Open complete folder"
|
||||
msgstr ""
|
||||
|
||||
@@ -1345,7 +1344,7 @@ msgstr ""
|
||||
msgid "Downloaded in %s at an average of %sB/s"
|
||||
msgstr ""
|
||||
|
||||
#. Job details page, file age column header
|
||||
#. Config->RSS filter-type selection menu (e.g. ">3d", "<12h") - Job details page, file age column header
|
||||
#: sabnzbd/nzb/object.py, sabnzbd/skintext.py
|
||||
msgid "Age"
|
||||
msgstr ""
|
||||
@@ -1430,6 +1429,21 @@ msgstr ""
|
||||
msgid "If you get this error message again, please try a different number.<br>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"\n"
|
||||
" SABnzbd is not allowed to use port %s on %s.<br>\n"
|
||||
" Low port numbers are reserved for privileged processes on most systems,\n"
|
||||
" so the port itself is available but cannot be claimed.<br>\n"
|
||||
" <br>\n"
|
||||
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
|
||||
" with a port number of 1024 or higher."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid "To keep using the low port, put a reverse proxy in front of SABnzbd instead.<br>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"\n"
|
||||
@@ -1492,19 +1506,15 @@ msgstr ""
|
||||
msgid "Unable to bind to port %s on %s. Some other software uses the port or SABnzbd is already running."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid "Not allowed to bind to port %s on %s. Low ports need elevated privileges."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/panic.py
|
||||
msgid "Cannot launch the browser, probably not found"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid "Access denied"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid "Error %s: You need to provide a valid username and password."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Old queue detected, use Status->Repair to convert the queue"
|
||||
@@ -1633,6 +1643,10 @@ msgstr ""
|
||||
msgid "Removing %s failed"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Removed %s files with unwanted extensions"
|
||||
msgstr ""
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/powersup.py
|
||||
msgid "Failed to hibernate system"
|
||||
@@ -1657,10 +1671,6 @@ msgstr ""
|
||||
msgid "Empty RSS entry found (%s)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/rss.py
|
||||
msgid "Incompatible feed"
|
||||
msgstr ""
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/rss.py
|
||||
msgid "Incorrect RSS feed description \"%s\""
|
||||
@@ -1682,50 +1692,15 @@ msgstr ""
|
||||
msgid "Server %s uses an untrusted HTTPS certificate"
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/rss.py
|
||||
msgid "RSS Feed %s was empty"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
msgid "Show interface"
|
||||
#: sabnzbd/rss.py
|
||||
msgid "Incompatible feed"
|
||||
msgstr ""
|
||||
|
||||
#. Queue page button or entry box
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 5 minutes"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 15 minutes"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 30 minutes"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 1 hour"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 3 hours"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 6 hours"
|
||||
msgstr ""
|
||||
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
msgid "Shutdown"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Remaining"
|
||||
msgstr ""
|
||||
|
||||
@@ -1733,6 +1708,44 @@ msgstr ""
|
||||
msgid "Add NZB"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Show interface"
|
||||
msgstr ""
|
||||
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Shutdown"
|
||||
msgstr ""
|
||||
|
||||
#. Queue page button or entry box
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 5 minutes"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 15 minutes"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 30 minutes"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 1 hour"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 3 hours"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 6 hours"
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/scheduler.py
|
||||
msgid "Bad schedule %s at %s:%s"
|
||||
@@ -2068,6 +2081,10 @@ msgstr ""
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Log in"
|
||||
msgstr ""
|
||||
@@ -2623,10 +2640,6 @@ msgstr ""
|
||||
msgid "Web Interface Theme"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Choose a theme."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "SABnzbd Username"
|
||||
msgstr ""
|
||||
@@ -2745,7 +2758,7 @@ msgid "Cleanup List"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "List of file extensions that should be deleted after download.<br />For example: <b>nfo</b> or <b>nfo, sfv</b>"
|
||||
msgid "List of file extensions, filenames or patterns that should be deleted after download.<br />Examples: <b>nfo, sfv</b> (extensions) or <b>thumbs.db</b> (filenames) or <b>*.tmp, images/*, */test.jpg</b> (patterns)."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3210,7 +3223,7 @@ msgid "Automatically sort jobs in the queue when a new job is added."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "The queue will resort every 30 seconds if % downloaded is selected."
|
||||
msgid "The queue will resort every 30 seconds if % downloaded or Remaining Size is selected."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3331,7 +3344,7 @@ msgid "Naming"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "How much can be downloaded this month (K/M/G)"
|
||||
msgid "How much can be downloaded this Quota period (K/M/G)"
|
||||
msgstr ""
|
||||
|
||||
#. Reset day of the download quota
|
||||
@@ -3584,10 +3597,6 @@ msgstr ""
|
||||
msgid "Force Download"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Apply filters"
|
||||
msgstr ""
|
||||
|
||||
#. Config->RSS edit button
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Edit"
|
||||
@@ -4212,6 +4221,14 @@ msgstr ""
|
||||
msgid "Filename"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Toggle SABnzbd navigation menu"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Open SABnzbd main menu"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Free Space"
|
||||
msgstr ""
|
||||
@@ -4220,6 +4237,14 @@ msgstr ""
|
||||
msgid "Temp Folder"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Clear search"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Search by name, or refine with filters <code>cat:</code>, <code>status:</code> and <code>priority:</code> (Queue). For example: <code>my show cat:tv</code>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Multi-Operations"
|
||||
msgstr ""
|
||||
@@ -4228,6 +4253,10 @@ msgstr ""
|
||||
msgid "Hold shift key to select a range"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Select job"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Check all"
|
||||
msgstr ""
|
||||
@@ -4260,6 +4289,10 @@ msgstr ""
|
||||
msgid "WARNING:"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "ERROR:"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Fetch"
|
||||
msgstr ""
|
||||
@@ -4296,6 +4329,14 @@ msgstr ""
|
||||
msgid "Extra history columns"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Progress"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "page"
|
||||
msgstr ""
|
||||
@@ -4456,6 +4497,10 @@ msgstr ""
|
||||
msgid "Sort by % downloaded <small>Most→Least</small>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Sort by Remaining Size <small>Smallest→Largest</small>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Sort by Age <small>Oldest→Newest</small>"
|
||||
msgstr ""
|
||||
|
||||
+1011
-711
File diff suppressed because it is too large.
Load diff
+205
-132
@@ -6,7 +6,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
|
||||
"Language-Team: Danish (https://app.transifex.com/sabnzbd/teams/111101/da/)\n"
|
||||
@@ -120,7 +120,6 @@ msgstr "SABnzbd %s startet"
|
||||
msgid "SABnzbd shutdown finished"
|
||||
msgstr "SABnzbd lukning udført"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/__init__.py
|
||||
msgid "Signal %s caught, saving and exiting..."
|
||||
msgstr "Signal %s modtaget, gemmer og lukker..."
|
||||
@@ -151,6 +150,7 @@ msgstr ""
|
||||
#: sabnzbd/__init__.py
|
||||
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
|
||||
msgstr ""
|
||||
"Windows ARM-versionen af SABnzbd er tilgængelig på vores downloadside!"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/__init__.py
|
||||
@@ -250,6 +250,10 @@ msgstr ""
|
||||
"Ukendt SSL protokol: Prøv at deaktivere SSL eller forbinder på en anden "
|
||||
"port."
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Could not determine connection result (%s)"
|
||||
msgstr "Det lykkedes ikke at tilslutte (%s)"
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Server requires username and password."
|
||||
msgstr "Serveren kræver brugernavn og adgangskode."
|
||||
@@ -258,18 +262,13 @@ msgstr "Serveren kræver brugernavn og adgangskode."
|
||||
msgid "Connection Successful!"
|
||||
msgstr "Tilslutning lykkedes!"
|
||||
|
||||
#: sabnzbd/api.py, sabnzbd/interface.py
|
||||
msgid "Authentication failed, check username/password."
|
||||
msgstr "Godkendelse mislykkedes, kontrollere brugernavn/adgangskode."
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/api.py
|
||||
msgid "Too many connections, please pause downloading or try again later"
|
||||
msgid ""
|
||||
"Server %s took %d ms to respond. On high-latency connections, increasing "
|
||||
"'Articles per request' to a value between 5 and 10 can improve download "
|
||||
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
|
||||
msgstr ""
|
||||
"Alt for mange forbindelser, pause en download eller forsøg igen senere"
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Could not determine connection result (%s)"
|
||||
msgstr "Det lykkedes ikke at tilslutte (%s)"
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Resolving address"
|
||||
@@ -286,12 +285,12 @@ msgid "Default"
|
||||
msgstr "Standard"
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/assembler.py
|
||||
#: sabnzbd/assembler.py, sabnzbd/decoder.py
|
||||
msgid "Disk full! Forcing Pause"
|
||||
msgstr "Disken er fuld! Pauser"
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/assembler.py
|
||||
#: sabnzbd/assembler.py, sabnzbd/decoder.py
|
||||
msgid "Disk error on creating file %s"
|
||||
msgstr "Diskfejl ved oprettelse af fil %s"
|
||||
|
||||
@@ -550,8 +549,8 @@ msgid "Resuming"
|
||||
msgstr "Genoptager"
|
||||
|
||||
#. PP status - Priority pick list
|
||||
#: sabnzbd/downloader.py, sabnzbd/macosmenu.py, sabnzbd/sabtray.py,
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/downloader.py, sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Paused"
|
||||
msgstr "Sat på pause"
|
||||
|
||||
@@ -591,26 +590,24 @@ msgid "Fatal error in Downloader"
|
||||
msgstr "Alvorlig fejl i Downloader"
|
||||
|
||||
#: sabnzbd/downloader.py
|
||||
msgid "Too many connections to server %s [%s]"
|
||||
msgstr "Alt for mange forbindelser til serveren %s [%s]"
|
||||
|
||||
#: sabnzbd/downloader.py
|
||||
msgid ""
|
||||
"Login from too many different IP addresses to server %s [%s] - "
|
||||
"https://sabnzbd.org/multiple-adresses"
|
||||
msgid "Server %s reported: %s"
|
||||
msgstr ""
|
||||
"Login fra for mange forskellige IP-adresser til server %s [%s] - "
|
||||
"https://sabnzbd.org/multiple-adresses"
|
||||
|
||||
#: sabnzbd/downloader.py
|
||||
msgid "Failed login for server %s [%s]"
|
||||
msgstr "Det lykkedes ikke at logge på serveren %s [%s]"
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/downloader.py
|
||||
msgid "Connecting %s@%s failed, message=%s"
|
||||
msgstr "Forbindelse %s@%s mislykkedes, besked %s"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/downloader.py
|
||||
msgid ""
|
||||
"Total number of configured connections (%d) is greater than the operating "
|
||||
"system limit (512), downloading will crash if all connections become active"
|
||||
msgstr ""
|
||||
"Det samlede antal konfigurerede forbindelser (%d) er større end "
|
||||
"operativsystemets grænse (512); downloadingen vil crashe, hvis alle "
|
||||
"forbindelser bliver aktive"
|
||||
|
||||
#: sabnzbd/downloader.py, sabnzbd/skintext.py
|
||||
msgid "Shutting down"
|
||||
msgstr "Påbegynder lukning af SABnzbd"
|
||||
@@ -776,15 +773,27 @@ msgid ""
|
||||
"files. For details and possible solutions, see: "
|
||||
"https://sabnzbd.org/wiki/advanced/direct-write"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Refused connection from:"
|
||||
msgstr "Afviste forbindelse fra:"
|
||||
"Direct Write-tilstand er blevet deaktiveret, fordi %s ikke understøtter "
|
||||
"sparse-filer. For detaljer og mulige løsninger, se: "
|
||||
"https://sabnzbd.org/wiki/advanced/direct-write"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Refused connection with hostname \"%s\" from:"
|
||||
msgstr "Afviste forbindelse med værtsnavn \"%s\" fra:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"API Key incorrect, Use the api key from Config->General in your 3rd party "
|
||||
"program:"
|
||||
msgstr ""
|
||||
"Forkert API-nøgle, anvend api-nøglen fra Konfiguration->Generelt i dit "
|
||||
"tredjepartsprogram:"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/interface.py, sabnzbd/security.py
|
||||
msgid "Refused connection from:"
|
||||
msgstr "Afviste forbindelse fra:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"API Key missing, please enter the api key from Config->General into your 3rd"
|
||||
@@ -794,21 +803,17 @@ msgstr ""
|
||||
"tredjepartsprogram:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"API Key incorrect, Use the api key from Config->General in your 3rd party "
|
||||
"program:"
|
||||
msgid "Too many failed login attempts, try again later."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Login attempt refused, too many failures from %s"
|
||||
msgstr ""
|
||||
"Forkert API-nøgle, anvend api-nøglen fra Konfiguration->Generelt i dit "
|
||||
"tredjepartsprogram:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "User logged in to the web interface"
|
||||
msgstr "Bruger logget på webgrænsefladen"
|
||||
|
||||
#. Notification
|
||||
#: sabnzbd/interface.py, sabnzbd/notifier.py
|
||||
msgid "User logged in"
|
||||
msgstr "Bruger logget ind"
|
||||
msgid "Authentication failed, check username/password."
|
||||
msgstr "Godkendelse mislykkedes, kontrollere brugernavn/adgangskode."
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/interface.py
|
||||
@@ -870,27 +875,20 @@ msgid ""
|
||||
msgstr ""
|
||||
"Kategorimappe kan ikke være en undermappe i den midlertidige download-mappe."
|
||||
|
||||
#: sabnzbd/interface.py, sabnzbd/skintext.py
|
||||
msgid "ERROR:"
|
||||
msgstr "FEJL:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Tilbage"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/internetspeed.py
|
||||
msgid ""
|
||||
"Internet Bandwidth of IPv4 significantly different from IPv6: %f MB/s versus"
|
||||
" %f MB/s"
|
||||
msgstr ""
|
||||
"Internetbåndbredde for IPv4 afviger markant fra IPv6: %f MB/s mod %f MB/s"
|
||||
|
||||
#. Footer: indicator of warnings
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/skintext.py
|
||||
msgid "Warnings"
|
||||
msgstr "Advarsler"
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py,
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Idle"
|
||||
msgstr "Inaktiv"
|
||||
@@ -921,8 +919,8 @@ msgstr "Hastighedsbegrænsning"
|
||||
|
||||
#. Notification - Pause downloading - Four way switch for duplicates -
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtray.py,
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
|
||||
@@ -932,8 +930,8 @@ msgid "min"
|
||||
msgstr "minut"
|
||||
|
||||
#. Notification - Resume downloading - Config->Scheduling
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtray.py,
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Resume"
|
||||
msgstr "Genoptag"
|
||||
|
||||
@@ -942,7 +940,7 @@ msgstr "Genoptag"
|
||||
msgid "Scan watched folder"
|
||||
msgstr "Scan overvåget mappe"
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Read all RSS feeds"
|
||||
msgstr "Læs alle RSS feeds"
|
||||
|
||||
@@ -954,17 +952,17 @@ msgstr "Færdig mappe"
|
||||
msgid "Incomplete Folder"
|
||||
msgstr "Ufuldstændig mappe"
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraywin.py
|
||||
msgid "Troubleshoot"
|
||||
msgstr "Fejlfinding"
|
||||
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py,
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Restart"
|
||||
msgstr "Genstart"
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraywin.py
|
||||
msgid "Restart without login"
|
||||
msgstr "Genstart uden login"
|
||||
|
||||
@@ -1161,6 +1159,11 @@ msgstr "Forsøger 7zip med adgangskode \"%s\""
|
||||
msgid "see logfile"
|
||||
msgstr "se logfil"
|
||||
|
||||
#: sabnzbd/newsunpack.py
|
||||
msgid "Unpacking skipped, TAR support requires Python 3.12 or later"
|
||||
msgstr ""
|
||||
"Udpakning sprunget over, TAR-understøttelse kræver Python 3.12 eller nyere"
|
||||
|
||||
#: sabnzbd/newsunpack.py
|
||||
msgid "Quick Checking"
|
||||
msgstr "Hurtig kontrollerende"
|
||||
@@ -1332,6 +1335,11 @@ msgstr "Jobbet misllykedes"
|
||||
msgid "Queue finished"
|
||||
msgstr "Kø færdig"
|
||||
|
||||
#. Notification
|
||||
#: sabnzbd/notifier.py
|
||||
msgid "User logged in"
|
||||
msgstr "Bruger logget ind"
|
||||
|
||||
#. Notification
|
||||
#: sabnzbd/notifier.py
|
||||
msgid "Other Messages"
|
||||
@@ -1343,7 +1351,7 @@ msgid "Open folder"
|
||||
msgstr "Åbn mappe"
|
||||
|
||||
#. Notification action
|
||||
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
#: sabnzbd/notifier.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Open complete folder"
|
||||
msgstr "Åben færdig mappe"
|
||||
|
||||
@@ -1482,7 +1490,8 @@ msgstr "PROPAGATING %s min"
|
||||
msgid "Downloaded in %s at an average of %sB/s"
|
||||
msgstr "Hentede i %s med et gennemsnit på %sB/s"
|
||||
|
||||
#. Job details page, file age column header
|
||||
#. Config->RSS filter-type selection menu (e.g. ">3d", "<12h") - Job details
|
||||
#. page, file age column header
|
||||
#: sabnzbd/nzb/object.py, sabnzbd/skintext.py
|
||||
msgid "Age"
|
||||
msgstr "Alder"
|
||||
@@ -1574,6 +1583,23 @@ msgid ""
|
||||
"If you get this error message again, please try a different number.<br>"
|
||||
msgstr "Hvis du får denne fejlmeddelelse igen, prøv et andet portnummer.<br>"
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"\n"
|
||||
" SABnzbd is not allowed to use port %s on %s.<br>\n"
|
||||
" Low port numbers are reserved for privileged processes on most systems,\n"
|
||||
" so the port itself is available but cannot be claimed.<br>\n"
|
||||
" <br>\n"
|
||||
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
|
||||
" with a port number of 1024 or higher."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"To keep using the low port, put a reverse proxy in front of SABnzbd "
|
||||
"instead.<br>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"\n"
|
||||
@@ -1662,19 +1688,16 @@ msgstr ""
|
||||
"Kan ikke binde til port %s på %s. En anden software bruger porten eller "
|
||||
"SABnzbd kører allerede."
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/panic.py
|
||||
msgid "Cannot launch the browser, probably not found"
|
||||
msgstr "Kan ikke starte browseren, sandsynligvis ikke fundet"
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid "Access denied"
|
||||
msgstr "Adgang nægtet"
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid "Error %s: You need to provide a valid username and password."
|
||||
msgstr "Fejl %s: Du skal angive et gyldigt brugernavn og adgangskode."
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Old queue detected, use Status->Repair to convert the queue"
|
||||
@@ -1803,6 +1826,10 @@ msgstr "Ingen matchende tidligere rar-fil for %s"
|
||||
msgid "Removing %s failed"
|
||||
msgstr "Fjernelse af %s mislykkedes"
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Removed %s files with unwanted extensions"
|
||||
msgstr ""
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/powersup.py
|
||||
msgid "Failed to hibernate system"
|
||||
@@ -1827,10 +1854,6 @@ msgstr "Modtog en DBus-undtagelse %s"
|
||||
msgid "Empty RSS entry found (%s)"
|
||||
msgstr "Tom RSS post blev fundet (%s)"
|
||||
|
||||
#: sabnzbd/rss.py
|
||||
msgid "Incompatible feed"
|
||||
msgstr "Inkompatibel feed"
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/rss.py
|
||||
msgid "Incorrect RSS feed description \"%s\""
|
||||
@@ -1852,50 +1875,15 @@ msgstr "Mislykkedes at hente RSS fra %s: %s"
|
||||
msgid "Server %s uses an untrusted HTTPS certificate"
|
||||
msgstr "Server %s bruger et upålideligt HTTPS-certifikat"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/rss.py
|
||||
msgid "RSS Feed %s was empty"
|
||||
msgstr "RSS Feed %s er tom"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
msgid "Show interface"
|
||||
msgstr "Vis grænseflade"
|
||||
#: sabnzbd/rss.py
|
||||
msgid "Incompatible feed"
|
||||
msgstr "Inkompatibel feed"
|
||||
|
||||
#. Queue page button or entry box
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for"
|
||||
msgstr "Pause i"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 5 minutes"
|
||||
msgstr "Pause 5 minutter"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 15 minutes"
|
||||
msgstr "Pause 15 minutter"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 30 minutes"
|
||||
msgstr "Pause 30 minutter"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 1 hour"
|
||||
msgstr "Pause 1 time"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 3 hours"
|
||||
msgstr "Pause 3 timer"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 6 hours"
|
||||
msgstr "Pause 6 timer"
|
||||
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
msgid "Shutdown"
|
||||
msgstr "Luk ned"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Remaining"
|
||||
msgstr "Tilbageværende"
|
||||
|
||||
@@ -1903,6 +1891,44 @@ msgstr "Tilbageværende"
|
||||
msgid "Add NZB"
|
||||
msgstr "Tilføj NZB"
|
||||
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Show interface"
|
||||
msgstr "Vis grænseflade"
|
||||
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Shutdown"
|
||||
msgstr "Luk ned"
|
||||
|
||||
#. Queue page button or entry box
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for"
|
||||
msgstr "Pause i"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 5 minutes"
|
||||
msgstr "Pause 5 minutter"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 15 minutes"
|
||||
msgstr "Pause 15 minutter"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 30 minutes"
|
||||
msgstr "Pause 30 minutter"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 1 hour"
|
||||
msgstr "Pause 1 time"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 3 hours"
|
||||
msgstr "Pause 3 timer"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 6 hours"
|
||||
msgstr "Pause 6 timer"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/scheduler.py
|
||||
msgid "Bad schedule %s at %s:%s"
|
||||
@@ -2238,6 +2264,10 @@ msgstr "Vært"
|
||||
msgid "Cancel"
|
||||
msgstr "Annullér"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Log in"
|
||||
msgstr "Log in"
|
||||
@@ -2824,10 +2854,6 @@ msgstr "Port som SABnzbd ska lytte på."
|
||||
msgid "Web Interface Theme"
|
||||
msgstr "Tema for webgrænseflade"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Choose a theme."
|
||||
msgstr "Vælg et tema."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "SABnzbd Username"
|
||||
msgstr "SABnzbd brugernavn"
|
||||
@@ -2972,11 +2998,13 @@ msgstr "Rydningsliste"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"List of file extensions that should be deleted after download.<br />For "
|
||||
"example: <b>nfo</b> or <b>nfo, sfv</b>"
|
||||
"List of file extensions, filenames or patterns that should be deleted after "
|
||||
"download.<br />Examples: <b>nfo, sfv</b> (extensions) or <b>thumbs.db</b> "
|
||||
"(filenames) or <b>*.tmp, images/*, */test.jpg</b> (patterns)."
|
||||
msgstr ""
|
||||
"Listen over filtypenavne, der skal slettes efter download.<br />For "
|
||||
"eksempel: <b>nfo</b> eller <b>nfo, sfv</b>"
|
||||
"Liste over filendelser, filnavne eller mønstre, der skal slettes efter "
|
||||
"download.<br />Eksempler: <b>nfo, sfv</b> (endelser) eller <b>thumbs.db</b> "
|
||||
"(filnavne) eller <b>*.tmp, images/*, */test.jpg</b> (mønstre)."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "History Retention"
|
||||
@@ -3356,6 +3384,9 @@ msgid ""
|
||||
"all jobs will be marked as Completed and moved to the Complete folder even "
|
||||
"if they are incomplete."
|
||||
msgstr ""
|
||||
"Forsøg kun at udpakke jobs, der har bestået verifikationen. Hvis dette er "
|
||||
"slået fra, markeres alle jobs som Færdig og flyttes til Færdig-mappen, "
|
||||
"selvom de er ufuldstændige."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Action when encrypted RAR is downloaded"
|
||||
@@ -3449,6 +3480,8 @@ msgstr "Aktiver SFV-baseret kontrol"
|
||||
msgid ""
|
||||
"If no par2 files are available, use sfv files (if present) to verify files"
|
||||
msgstr ""
|
||||
"Hvis ingen par2-filer er tilgængelige, brug da sfv-filer (hvis til stede) "
|
||||
"til at verificere filer"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "User script can flag job as failed"
|
||||
@@ -3523,8 +3556,10 @@ msgid "Automatically sort jobs in the queue when a new job is added."
|
||||
msgstr "Sortér automatisk jobs i køen, når et nyt job tilføjes."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "The queue will resort every 30 seconds if % downloaded is selected."
|
||||
msgstr "Køen vil sortere hver 30. sekund, hvis % downloadet er valgt."
|
||||
msgid ""
|
||||
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
|
||||
"selected."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Propagation delay"
|
||||
@@ -3663,8 +3698,8 @@ msgid "Naming"
|
||||
msgstr "Navngivning"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "How much can be downloaded this month (K/M/G)"
|
||||
msgstr "Hvor meget der kan downloades i denne måned (K/M/G)"
|
||||
msgid "How much can be downloaded this Quota period (K/M/G)"
|
||||
msgstr ""
|
||||
|
||||
#. Reset day of the download quota
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3865,7 +3900,7 @@ msgstr "Aktivere"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Articles per request"
|
||||
msgstr ""
|
||||
msgstr "Artikler pr. forespørgsel"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
@@ -3873,6 +3908,9 @@ msgid ""
|
||||
"first.<br />This can improve download speeds, especially on connections with"
|
||||
" higher latency."
|
||||
msgstr ""
|
||||
"Anmod om flere artikler pr. forbindelse uden først at vente på hvert "
|
||||
"svar.<br />Dette kan forbedre downloadhastighederne, især på forbindelser "
|
||||
"med højere latens."
|
||||
|
||||
#. Button: Remove server
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3961,10 +3999,6 @@ msgstr "Læs Feed"
|
||||
msgid "Force Download"
|
||||
msgstr "Gennemtving download"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Apply filters"
|
||||
msgstr "Anvend filtre"
|
||||
|
||||
#. Config->RSS edit button
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Edit"
|
||||
@@ -4649,6 +4683,14 @@ msgstr "Slet"
|
||||
msgid "Filename"
|
||||
msgstr "Filnavn"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Toggle SABnzbd navigation menu"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Open SABnzbd main menu"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Free Space"
|
||||
msgstr "Ledig diskplads"
|
||||
@@ -4657,6 +4699,17 @@ msgstr "Ledig diskplads"
|
||||
msgid "Temp Folder"
|
||||
msgstr "Midlertidig mappe"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Clear search"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Search by name, or refine with filters <code>cat:</code>, "
|
||||
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
|
||||
"<code>my show cat:tv</code>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Multi-Operations"
|
||||
msgstr "Multi-operationer"
|
||||
@@ -4665,6 +4718,10 @@ msgstr "Multi-operationer"
|
||||
msgid "Hold shift key to select a range"
|
||||
msgstr "Hold Skiftetasten nede for at vælge et område"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Select job"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Check all"
|
||||
msgstr "Tjek alle"
|
||||
@@ -4697,6 +4754,10 @@ msgstr "I tilfælde af SABnzbd genstart vil denne skærm forsvinde automatisk!"
|
||||
msgid "WARNING:"
|
||||
msgstr "ADVARSEL:"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "ERROR:"
|
||||
msgstr "FEJL:"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Fetch"
|
||||
msgstr "Hent"
|
||||
@@ -4733,6 +4794,14 @@ msgstr "Ekstra køkolonner"
|
||||
msgid "Extra history columns"
|
||||
msgstr "Ekstra historikkolonner"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Progress"
|
||||
msgstr "Fremgang"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Actions"
|
||||
msgstr "Handlinger"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "page"
|
||||
msgstr "side"
|
||||
@@ -4909,6 +4978,10 @@ msgstr ""
|
||||
msgid "Sort by % downloaded <small>Most→Least</small>"
|
||||
msgstr "Sortér efter % downloadet <small>Mest→Mindst</small>"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Sort by Remaining Size <small>Smallest→Largest</small>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Sort by Age <small>Oldest→Newest</small>"
|
||||
msgstr "Sortere efter alder <small>Ældst→Nyeste</small>"
|
||||
|
||||
+209
-136
@@ -20,7 +20,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
|
||||
"Language-Team: German (https://app.transifex.com/sabnzbd/teams/111101/de/)\n"
|
||||
@@ -138,7 +138,6 @@ msgstr "SABnzbd %s gestartet"
|
||||
msgid "SABnzbd shutdown finished"
|
||||
msgstr "SABnzbd wurde beendet"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/__init__.py
|
||||
msgid "Signal %s caught, saving and exiting..."
|
||||
msgstr "Signal %s erkannt. Wird gespeichert und beendet …"
|
||||
@@ -171,6 +170,8 @@ msgstr ""
|
||||
#: sabnzbd/__init__.py
|
||||
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
|
||||
msgstr ""
|
||||
"Eine Windows-ARM-Version von SABnzbd ist auf unserer Downloads-Seite "
|
||||
"verfügbar!"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/__init__.py
|
||||
@@ -274,6 +275,10 @@ msgstr ""
|
||||
"Unbekanntes SSL-Protokoll: SSL deaktivieren oder alternativen Port "
|
||||
"versuchen."
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Could not determine connection result (%s)"
|
||||
msgstr "Die Verbindung konnte nicht überprüft werden. (%s)"
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Server requires username and password."
|
||||
msgstr "Server benötigt ein Benutzername und ein Passwort."
|
||||
@@ -282,20 +287,13 @@ msgstr "Server benötigt ein Benutzername und ein Passwort."
|
||||
msgid "Connection Successful!"
|
||||
msgstr "Verbindung erfolgreich hergestellt!"
|
||||
|
||||
#: sabnzbd/api.py, sabnzbd/interface.py
|
||||
msgid "Authentication failed, check username/password."
|
||||
msgstr ""
|
||||
"Authentifizierung fehlgeschlagen. Überprüfen Sie Benutzername und Passwort."
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/api.py
|
||||
msgid "Too many connections, please pause downloading or try again later"
|
||||
msgid ""
|
||||
"Server %s took %d ms to respond. On high-latency connections, increasing "
|
||||
"'Articles per request' to a value between 5 and 10 can improve download "
|
||||
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
|
||||
msgstr ""
|
||||
"Zu viele Verbindungen. Bitte halten Sie die Downloads an oder versuchen Sie "
|
||||
"es später erneut."
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Could not determine connection result (%s)"
|
||||
msgstr "Die Verbindung konnte nicht überprüft werden. (%s)"
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Resolving address"
|
||||
@@ -312,12 +310,12 @@ msgid "Default"
|
||||
msgstr "Standard"
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/assembler.py
|
||||
#: sabnzbd/assembler.py, sabnzbd/decoder.py
|
||||
msgid "Disk full! Forcing Pause"
|
||||
msgstr "Festplatte voll! Downloads werden angehalten."
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/assembler.py
|
||||
#: sabnzbd/assembler.py, sabnzbd/decoder.py
|
||||
msgid "Disk error on creating file %s"
|
||||
msgstr "Festplattenfehler beim Anlegen der Datei %s"
|
||||
|
||||
@@ -582,8 +580,8 @@ msgid "Resuming"
|
||||
msgstr "Fortgesetzt"
|
||||
|
||||
#. PP status - Priority pick list
|
||||
#: sabnzbd/downloader.py, sabnzbd/macosmenu.py, sabnzbd/sabtray.py,
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/downloader.py, sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Paused"
|
||||
msgstr "Angehalten"
|
||||
|
||||
@@ -623,26 +621,24 @@ msgid "Fatal error in Downloader"
|
||||
msgstr "Schwerer Fehler im Downloader"
|
||||
|
||||
#: sabnzbd/downloader.py
|
||||
msgid "Too many connections to server %s [%s]"
|
||||
msgstr "Zu viele Verbindungen zu Server %s [%s]"
|
||||
|
||||
#: sabnzbd/downloader.py
|
||||
msgid ""
|
||||
"Login from too many different IP addresses to server %s [%s] - "
|
||||
"https://sabnzbd.org/multiple-adresses"
|
||||
msgid "Server %s reported: %s"
|
||||
msgstr ""
|
||||
"Von zu vielen unteschiedlichen IP Adressen beim Server eingeloggt %s[%s] "
|
||||
"https://sabnzbd.org/multiple-adresses"
|
||||
|
||||
#: sabnzbd/downloader.py
|
||||
msgid "Failed login for server %s [%s]"
|
||||
msgstr "Anmelden beim Server fehlgeschlagen. %s [%s]"
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/downloader.py
|
||||
msgid "Connecting %s@%s failed, message=%s"
|
||||
msgstr "Fehler beim Verbinden mit %s@%s, Meldung = %s"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/downloader.py
|
||||
msgid ""
|
||||
"Total number of configured connections (%d) is greater than the operating "
|
||||
"system limit (512), downloading will crash if all connections become active"
|
||||
msgstr ""
|
||||
"Die Gesamtzahl der konfigurierten Verbindungen (%d) ist größer als das Limit"
|
||||
" des Betriebssystems (512); das Herunterladen stürzt ab, wenn alle "
|
||||
"Verbindungen aktiv werden"
|
||||
|
||||
#: sabnzbd/downloader.py, sabnzbd/skintext.py
|
||||
msgid "Shutting down"
|
||||
msgstr "Wird beendet …"
|
||||
@@ -815,15 +811,27 @@ msgid ""
|
||||
"files. For details and possible solutions, see: "
|
||||
"https://sabnzbd.org/wiki/advanced/direct-write"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Refused connection from:"
|
||||
msgstr "Abgelehnte Verbindung von:"
|
||||
"Der Direct-Write-Modus wurde deaktiviert, weil %s keine Sparse-Dateien "
|
||||
"unterstützt. Einzelheiten und mögliche Lösungen finden Sie unter: "
|
||||
"https://sabnzbd.org/wiki/advanced/direct-write"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Refused connection with hostname \"%s\" from:"
|
||||
msgstr "Verbindung vom Host \"%s\" abgelehnt von:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"API Key incorrect, Use the api key from Config->General in your 3rd party "
|
||||
"program:"
|
||||
msgstr ""
|
||||
"API-Schlüssel ungültig. Bitte API-Schlüssel aus Einstellungen->Allgemein in "
|
||||
"die externe Anwendung eingeben:"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/interface.py, sabnzbd/security.py
|
||||
msgid "Refused connection from:"
|
||||
msgstr "Abgelehnte Verbindung von:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"API Key missing, please enter the api key from Config->General into your 3rd"
|
||||
@@ -833,21 +841,18 @@ msgstr ""
|
||||
" externe Anwendung eingeben:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"API Key incorrect, Use the api key from Config->General in your 3rd party "
|
||||
"program:"
|
||||
msgid "Too many failed login attempts, try again later."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Login attempt refused, too many failures from %s"
|
||||
msgstr ""
|
||||
"API-Schlüssel ungültig. Bitte API-Schlüssel aus Einstellungen->Allgemein in "
|
||||
"die externe Anwendung eingeben:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "User logged in to the web interface"
|
||||
msgstr "Benutzer im Web-Interface angemeldet"
|
||||
|
||||
#. Notification
|
||||
#: sabnzbd/interface.py, sabnzbd/notifier.py
|
||||
msgid "User logged in"
|
||||
msgstr "Benutzer angemeldet"
|
||||
msgid "Authentication failed, check username/password."
|
||||
msgstr ""
|
||||
"Authentifizierung fehlgeschlagen. Überprüfen Sie Benutzername und Passwort."
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/interface.py
|
||||
@@ -910,27 +915,21 @@ msgstr ""
|
||||
"Der Category-Ordner darf kein Unterordner des Temporärer Download-Ordners "
|
||||
"sein."
|
||||
|
||||
#: sabnzbd/interface.py, sabnzbd/skintext.py
|
||||
msgid "ERROR:"
|
||||
msgstr "FEHLER:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Zurück"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/internetspeed.py
|
||||
msgid ""
|
||||
"Internet Bandwidth of IPv4 significantly different from IPv6: %f MB/s versus"
|
||||
" %f MB/s"
|
||||
msgstr ""
|
||||
"Internet Bandbreite von IPv4 weicht deutlich von IPv6 ab: %f MB/s gegenüber "
|
||||
"%f MB/s"
|
||||
|
||||
#. Footer: indicator of warnings
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/skintext.py
|
||||
msgid "Warnings"
|
||||
msgstr "Warnungen"
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py,
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Idle"
|
||||
msgstr "Leerlauf"
|
||||
@@ -961,8 +960,8 @@ msgstr "Geschwindigkeit begrenzen"
|
||||
|
||||
#. Notification - Pause downloading - Four way switch for duplicates -
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtray.py,
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause"
|
||||
msgstr "Anhalten"
|
||||
|
||||
@@ -972,8 +971,8 @@ msgid "min"
|
||||
msgstr "Minuten"
|
||||
|
||||
#. Notification - Resume downloading - Config->Scheduling
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtray.py,
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Resume"
|
||||
msgstr "Fortsetzen"
|
||||
|
||||
@@ -982,7 +981,7 @@ msgstr "Fortsetzen"
|
||||
msgid "Scan watched folder"
|
||||
msgstr "Überwachter Ordner lesen"
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Read all RSS feeds"
|
||||
msgstr "Alle RSS-Feeds lesen"
|
||||
|
||||
@@ -994,17 +993,17 @@ msgstr "Fertige Downloads"
|
||||
msgid "Incomplete Folder"
|
||||
msgstr "Unfertige Download"
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraywin.py
|
||||
msgid "Troubleshoot"
|
||||
msgstr "Fehler suchen"
|
||||
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py,
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Restart"
|
||||
msgstr "Neu starten"
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraywin.py
|
||||
msgid "Restart without login"
|
||||
msgstr "Neustart ohne Anmeldung"
|
||||
|
||||
@@ -1204,6 +1203,11 @@ msgstr "Versuche 7zip mit Passwort \"%s\""
|
||||
msgid "see logfile"
|
||||
msgstr "Beachten Sie die Protokolldatei"
|
||||
|
||||
#: sabnzbd/newsunpack.py
|
||||
msgid "Unpacking skipped, TAR support requires Python 3.12 or later"
|
||||
msgstr ""
|
||||
"Entpacken übersprungen, TAR-Unterstützung erfordert Python 3.12 oder neuer"
|
||||
|
||||
#: sabnzbd/newsunpack.py
|
||||
msgid "Quick Checking"
|
||||
msgstr "Schnelle Überprüfung"
|
||||
@@ -1378,6 +1382,11 @@ msgstr "Auftrag fehlgeschlagen"
|
||||
msgid "Queue finished"
|
||||
msgstr "Warteschlange abgearbeitet"
|
||||
|
||||
#. Notification
|
||||
#: sabnzbd/notifier.py
|
||||
msgid "User logged in"
|
||||
msgstr "Benutzer angemeldet"
|
||||
|
||||
#. Notification
|
||||
#: sabnzbd/notifier.py
|
||||
msgid "Other Messages"
|
||||
@@ -1389,7 +1398,7 @@ msgid "Open folder"
|
||||
msgstr "Ordner öffnen"
|
||||
|
||||
#. Notification action
|
||||
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
#: sabnzbd/notifier.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Open complete folder"
|
||||
msgstr "Öffne Zielverzeichnis"
|
||||
|
||||
@@ -1532,7 +1541,8 @@ msgid "Downloaded in %s at an average of %sB/s"
|
||||
msgstr ""
|
||||
"Heruntergeladen in %s mit einer Durchschnittsgeschwindigkeit von %sB/s"
|
||||
|
||||
#. Job details page, file age column header
|
||||
#. Config->RSS filter-type selection menu (e.g. ">3d", "<12h") - Job details
|
||||
#. page, file age column header
|
||||
#: sabnzbd/nzb/object.py, sabnzbd/skintext.py
|
||||
msgid "Age"
|
||||
msgstr "Alter"
|
||||
@@ -1626,6 +1636,23 @@ msgstr ""
|
||||
"Wenn Sie diesen Fehler wieder erhalten, probieren Sie eine andere "
|
||||
"Nummer.<br>"
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"\n"
|
||||
" SABnzbd is not allowed to use port %s on %s.<br>\n"
|
||||
" Low port numbers are reserved for privileged processes on most systems,\n"
|
||||
" so the port itself is available but cannot be claimed.<br>\n"
|
||||
" <br>\n"
|
||||
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
|
||||
" with a port number of 1024 or higher."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"To keep using the low port, put a reverse proxy in front of SABnzbd "
|
||||
"instead.<br>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"\n"
|
||||
@@ -1714,6 +1741,11 @@ msgstr ""
|
||||
"Konnte nicht an Port %s auf %s starten. Eine andere Software nutzt diesen "
|
||||
"Port oder SABnzbd läuft bereits."
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/panic.py
|
||||
msgid "Cannot launch the browser, probably not found"
|
||||
@@ -1721,15 +1753,6 @@ msgstr ""
|
||||
"Der Standard-Browser konnte nicht gestartet werden, da er wahrscheinlich "
|
||||
"nicht gefunden wurde."
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid "Access denied"
|
||||
msgstr "Zugriff verweigert"
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid "Error %s: You need to provide a valid username and password."
|
||||
msgstr ""
|
||||
"Fehler %s: Sie müssen einen gültigen Benutzername und ein Passwort angeben."
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Old queue detected, use Status->Repair to convert the queue"
|
||||
@@ -1862,6 +1885,10 @@ msgstr "Keine zugehörige frühere RAR-Datei für %s"
|
||||
msgid "Removing %s failed"
|
||||
msgstr "Entfernen von %s fehlgeschlagen"
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Removed %s files with unwanted extensions"
|
||||
msgstr ""
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/powersup.py
|
||||
msgid "Failed to hibernate system"
|
||||
@@ -1886,10 +1913,6 @@ msgstr "DBus-Ausnahmefehler empfangen %s "
|
||||
msgid "Empty RSS entry found (%s)"
|
||||
msgstr "Leerer RSS-Feed gefunden: %s"
|
||||
|
||||
#: sabnzbd/rss.py
|
||||
msgid "Incompatible feed"
|
||||
msgstr "Inkompatibeler RSS-Feed"
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/rss.py
|
||||
msgid "Incorrect RSS feed description \"%s\""
|
||||
@@ -1911,50 +1934,15 @@ msgstr "Abrufen des RSS-Feeds von %s fehlgeschlagen: %s"
|
||||
msgid "Server %s uses an untrusted HTTPS certificate"
|
||||
msgstr "Der Server %s nutzt ein nicht vertrauenswürdiges HTTPS-Zertifikat"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/rss.py
|
||||
msgid "RSS Feed %s was empty"
|
||||
msgstr "RSS-Feed %s war leer"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
msgid "Show interface"
|
||||
msgstr "Interface anzeigen"
|
||||
#: sabnzbd/rss.py
|
||||
msgid "Incompatible feed"
|
||||
msgstr "Inkompatibeler RSS-Feed"
|
||||
|
||||
#. Queue page button or entry box
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for"
|
||||
msgstr "Anhalten für"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 5 minutes"
|
||||
msgstr "5 Minuten anhalten"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 15 minutes"
|
||||
msgstr "15 Minuten anhalten"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 30 minutes"
|
||||
msgstr "30 Minuten anhalten"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 1 hour"
|
||||
msgstr "Eine Stunde anhalten"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 3 hours"
|
||||
msgstr "3 Stunden anhalten"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 6 hours"
|
||||
msgstr "6 Stunden anhalten"
|
||||
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
msgid "Shutdown"
|
||||
msgstr "Beenden"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Remaining"
|
||||
msgstr "Verbleibend"
|
||||
|
||||
@@ -1962,6 +1950,44 @@ msgstr "Verbleibend"
|
||||
msgid "Add NZB"
|
||||
msgstr "NZB hinzufügen"
|
||||
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Show interface"
|
||||
msgstr "Interface anzeigen"
|
||||
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Shutdown"
|
||||
msgstr "Beenden"
|
||||
|
||||
#. Queue page button or entry box
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for"
|
||||
msgstr "Anhalten für"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 5 minutes"
|
||||
msgstr "5 Minuten anhalten"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 15 minutes"
|
||||
msgstr "15 Minuten anhalten"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 30 minutes"
|
||||
msgstr "30 Minuten anhalten"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 1 hour"
|
||||
msgstr "Eine Stunde anhalten"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 3 hours"
|
||||
msgstr "3 Stunden anhalten"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 6 hours"
|
||||
msgstr "6 Stunden anhalten"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/scheduler.py
|
||||
msgid "Bad schedule %s at %s:%s"
|
||||
@@ -2297,6 +2323,10 @@ msgstr "Adresse"
|
||||
msgid "Cancel"
|
||||
msgstr "Abbrechen"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Log in"
|
||||
msgstr "Anmelden"
|
||||
@@ -2888,10 +2918,6 @@ msgstr "Port, auf dem SABnzbd auf Anfragen warten soll."
|
||||
msgid "Web Interface Theme"
|
||||
msgstr "Benutzeroberfläche"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Choose a theme."
|
||||
msgstr "Wählen Sie ein Theme."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "SABnzbd Username"
|
||||
msgstr "SABnzbd-Benutzername"
|
||||
@@ -3043,11 +3069,14 @@ msgstr "Unerwünschte Dateien"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"List of file extensions that should be deleted after download.<br />For "
|
||||
"example: <b>nfo</b> or <b>nfo, sfv</b>"
|
||||
"List of file extensions, filenames or patterns that should be deleted after "
|
||||
"download.<br />Examples: <b>nfo, sfv</b> (extensions) or <b>thumbs.db</b> "
|
||||
"(filenames) or <b>*.tmp, images/*, */test.jpg</b> (patterns)."
|
||||
msgstr ""
|
||||
"Liste der Dateiendungen, die nach dem Download gelöscht werden sollen.<br "
|
||||
"/>Zum Beispiel:<b>nfo</b> or <b>nfo,sfv</b>"
|
||||
"Liste von Dateierweiterungen, Dateinamen oder Mustern, die nach dem Download"
|
||||
" gelöscht werden sollen.<br />Beispiele: <b>nfo, sfv</b> (Erweiterungen) "
|
||||
"oder <b>thumbs.db</b> (Dateinamen) oder <b>*.tmp, images/*, */test.jpg</b> "
|
||||
"(Muster)."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "History Retention"
|
||||
@@ -3444,6 +3473,10 @@ msgid ""
|
||||
"all jobs will be marked as Completed and moved to the Complete folder even "
|
||||
"if they are incomplete."
|
||||
msgstr ""
|
||||
"Nur Aufträge entpacken, welche die Überprüfung bestanden haben. Wenn "
|
||||
"deaktiviert, werden alle Aufträge als Fertiggestellt markiert und in den "
|
||||
"\"Abgeschlossene Downloads\"-Ordner verschoben, auch wenn sie unvollständig "
|
||||
"sind."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Action when encrypted RAR is downloaded"
|
||||
@@ -3539,6 +3572,8 @@ msgstr "SFV-basierte Überprüfung aktivieren"
|
||||
msgid ""
|
||||
"If no par2 files are available, use sfv files (if present) to verify files"
|
||||
msgstr ""
|
||||
"Wenn keine par2-Dateien verfügbar sind, sfv-Dateien (falls vorhanden) zur "
|
||||
"Überprüfung der Dateien verwenden"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "User script can flag job as failed"
|
||||
@@ -3619,10 +3654,10 @@ msgstr ""
|
||||
"Warteschlange automatisch sortieren wenn ein neuer Job hinzugefügt wird."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "The queue will resort every 30 seconds if % downloaded is selected."
|
||||
msgid ""
|
||||
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
|
||||
"selected."
|
||||
msgstr ""
|
||||
"Die Warteschlange wird alle 30 Sekunden neu sortiert, wenn % "
|
||||
"heruntergeladen, ausgewählt ist."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Propagation delay"
|
||||
@@ -3765,8 +3800,8 @@ msgid "Naming"
|
||||
msgstr "Benennung"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "How much can be downloaded this month (K/M/G)"
|
||||
msgstr "Wie viel kann in diesem Monat heruntergeladen werden (K/M/G)?"
|
||||
msgid "How much can be downloaded this Quota period (K/M/G)"
|
||||
msgstr ""
|
||||
|
||||
#. Reset day of the download quota
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3973,7 +4008,7 @@ msgstr "Aktivieren"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Articles per request"
|
||||
msgstr ""
|
||||
msgstr "Artikel pro Anfrage"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
@@ -3981,6 +4016,9 @@ msgid ""
|
||||
"first.<br />This can improve download speeds, especially on connections with"
|
||||
" higher latency."
|
||||
msgstr ""
|
||||
"Mehrere Artikel pro Verbindung anfordern, ohne zuerst auf jede Antwort zu "
|
||||
"warten.<br />Dies kann die Download-Geschwindigkeit verbessern, insbesondere"
|
||||
" bei Verbindungen mit höherer Latenz."
|
||||
|
||||
#. Button: Remove server
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -4069,10 +4107,6 @@ msgstr "Feed lesen"
|
||||
msgid "Force Download"
|
||||
msgstr "Download erzwingen"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Apply filters"
|
||||
msgstr "Filter übernehmen"
|
||||
|
||||
#. Config->RSS edit button
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Edit"
|
||||
@@ -4765,6 +4799,14 @@ msgstr "Löschen"
|
||||
msgid "Filename"
|
||||
msgstr "Dateiname"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Toggle SABnzbd navigation menu"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Open SABnzbd main menu"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Free Space"
|
||||
msgstr "Freier Speicherplatz"
|
||||
@@ -4773,6 +4815,17 @@ msgstr "Freier Speicherplatz"
|
||||
msgid "Temp Folder"
|
||||
msgstr "Temporärer Ordner"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Clear search"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Search by name, or refine with filters <code>cat:</code>, "
|
||||
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
|
||||
"<code>my show cat:tv</code>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Multi-Operations"
|
||||
msgstr "Mehrfach-Funktionen"
|
||||
@@ -4781,6 +4834,10 @@ msgstr "Mehrfach-Funktionen"
|
||||
msgid "Hold shift key to select a range"
|
||||
msgstr "Shift-Taste gedrückt halten, um einen ganzen Bereich auszuwählen"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Select job"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Check all"
|
||||
msgstr "Alle auswählen"
|
||||
@@ -4813,6 +4870,10 @@ msgstr "Wenn SABnzbd neustartet, wird diese Anzeige automatisch verschwinden!"
|
||||
msgid "WARNING:"
|
||||
msgstr "WARNUNG:"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "ERROR:"
|
||||
msgstr "FEHLER:"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Fetch"
|
||||
msgstr "Abrufen"
|
||||
@@ -4849,6 +4910,14 @@ msgstr "Weitere Spalten bei der Warteschlange"
|
||||
msgid "Extra history columns"
|
||||
msgstr "Weitere Spalten bei der Verlaufsliste"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Progress"
|
||||
msgstr "Fortschritt"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Actions"
|
||||
msgstr "Aktionen"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "page"
|
||||
msgstr "Seite"
|
||||
@@ -5026,6 +5095,10 @@ msgstr ""
|
||||
msgid "Sort by % downloaded <small>Most→Least</small>"
|
||||
msgstr "Sortiere nach % heruntergeladen <small>Viel→Wenig</small>"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Sort by Remaining Size <small>Smallest→Largest</small>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Sort by Age <small>Oldest→Newest</small>"
|
||||
msgstr "Sortieren nach Alter <small>Älteste→Neuste</small>"
|
||||
|
||||
+209
-132
@@ -9,7 +9,7 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-5.0.0\n"
|
||||
"Project-Id-Version: SABnzbd-5.2.0\n"
|
||||
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
|
||||
"Language-Team: Spanish (https://app.transifex.com/sabnzbd/teams/111101/es/)\n"
|
||||
@@ -127,7 +127,6 @@ msgstr "SABnzbd %s comenzó"
|
||||
msgid "SABnzbd shutdown finished"
|
||||
msgstr "Cierre de SABnzbd terminado"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/__init__.py
|
||||
msgid "Signal %s caught, saving and exiting..."
|
||||
msgstr "Señal %s capturado, guardando y saliendo..."
|
||||
@@ -160,6 +159,8 @@ msgstr ""
|
||||
#: sabnzbd/__init__.py
|
||||
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
|
||||
msgstr ""
|
||||
"¡La versión Windows ARM de SABnzbd está disponible en nuestra página de "
|
||||
"descargas!"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/__init__.py
|
||||
@@ -259,6 +260,10 @@ msgstr ""
|
||||
"Protocolo SSL desconocido: intente desabilitar el SSL o conectarse a un "
|
||||
"puerto diferente."
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Could not determine connection result (%s)"
|
||||
msgstr "No se pudo determinar el resultado de la conexión (%s)"
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Server requires username and password."
|
||||
msgstr "El servidor necesita usuario y contraseña."
|
||||
@@ -267,18 +272,13 @@ msgstr "El servidor necesita usuario y contraseña."
|
||||
msgid "Connection Successful!"
|
||||
msgstr "¡Conexión exitosa!"
|
||||
|
||||
#: sabnzbd/api.py, sabnzbd/interface.py
|
||||
msgid "Authentication failed, check username/password."
|
||||
msgstr "Autenticación fallida, compruebe el usuario o la contraseña."
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/api.py
|
||||
msgid "Too many connections, please pause downloading or try again later"
|
||||
msgid ""
|
||||
"Server %s took %d ms to respond. On high-latency connections, increasing "
|
||||
"'Articles per request' to a value between 5 and 10 can improve download "
|
||||
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
|
||||
msgstr ""
|
||||
"Demasiadas conexiones; pause las descargas o inténtelo de nuevo más tarde"
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Could not determine connection result (%s)"
|
||||
msgstr "No se pudo determinar el resultado de la conexión (%s)"
|
||||
|
||||
#: sabnzbd/api.py
|
||||
msgid "Resolving address"
|
||||
@@ -295,12 +295,12 @@ msgid "Default"
|
||||
msgstr "Predeterminado"
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/assembler.py
|
||||
#: sabnzbd/assembler.py, sabnzbd/decoder.py
|
||||
msgid "Disk full! Forcing Pause"
|
||||
msgstr "Disco lleno! Pausando la cola"
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/assembler.py
|
||||
#: sabnzbd/assembler.py, sabnzbd/decoder.py
|
||||
msgid "Disk error on creating file %s"
|
||||
msgstr "Error de disco al crear el archivo %s"
|
||||
|
||||
@@ -567,8 +567,8 @@ msgid "Resuming"
|
||||
msgstr "Reanudando"
|
||||
|
||||
#. PP status - Priority pick list
|
||||
#: sabnzbd/downloader.py, sabnzbd/macosmenu.py, sabnzbd/sabtray.py,
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/downloader.py, sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Paused"
|
||||
msgstr "En pausa"
|
||||
|
||||
@@ -608,26 +608,24 @@ msgid "Fatal error in Downloader"
|
||||
msgstr "Error grave en el descargador"
|
||||
|
||||
#: sabnzbd/downloader.py
|
||||
msgid "Too many connections to server %s [%s]"
|
||||
msgstr "Demasiadas conexiones con el servidor %s [%s]"
|
||||
|
||||
#: sabnzbd/downloader.py
|
||||
msgid ""
|
||||
"Login from too many different IP addresses to server %s [%s] - "
|
||||
"https://sabnzbd.org/multiple-adresses"
|
||||
msgid "Server %s reported: %s"
|
||||
msgstr ""
|
||||
"Inicio de sesión desde demasiadas direcciones IP diferentes en el servidor "
|
||||
"%s [%s] - https://sabnzbd.org/multiple-adresses"
|
||||
|
||||
#: sabnzbd/downloader.py
|
||||
msgid "Failed login for server %s [%s]"
|
||||
msgstr "Registraccion fallo para servidor %s [%s]"
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/downloader.py
|
||||
msgid "Connecting %s@%s failed, message=%s"
|
||||
msgstr "Ha fallado la conexión a %s@%s, el mensaje=%s"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/downloader.py
|
||||
msgid ""
|
||||
"Total number of configured connections (%d) is greater than the operating "
|
||||
"system limit (512), downloading will crash if all connections become active"
|
||||
msgstr ""
|
||||
"El número total de conexiones configuradas (%d) es mayor que el límite del "
|
||||
"sistema operativo (512); la descarga se bloqueará si todas las conexiones se"
|
||||
" activan"
|
||||
|
||||
#: sabnzbd/downloader.py, sabnzbd/skintext.py
|
||||
msgid "Shutting down"
|
||||
msgstr "Apagando"
|
||||
@@ -799,15 +797,27 @@ msgid ""
|
||||
"files. For details and possible solutions, see: "
|
||||
"https://sabnzbd.org/wiki/advanced/direct-write"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Refused connection from:"
|
||||
msgstr "Conexión rechazada de:"
|
||||
"El modo Direct Write se ha desactivado porque %s no admite archivos "
|
||||
"dispersos. Para más detalles y posibles soluciones, consulta: "
|
||||
"https://sabnzbd.org/wiki/advanced/direct-write"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Refused connection with hostname \"%s\" from:"
|
||||
msgstr "Se deniega la conexión con el nombre de equipo \"%s\" desde:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"API Key incorrect, Use the api key from Config->General in your 3rd party "
|
||||
"program:"
|
||||
msgstr ""
|
||||
"Clave de API erróneo, favor ingresar la clave correcta desde Config->General"
|
||||
" en tu aplicacion externa:"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/interface.py, sabnzbd/security.py
|
||||
msgid "Refused connection from:"
|
||||
msgstr "Conexión rechazada de:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"API Key missing, please enter the api key from Config->General into your 3rd"
|
||||
@@ -817,21 +827,17 @@ msgstr ""
|
||||
"aplicacion externa:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"API Key incorrect, Use the api key from Config->General in your 3rd party "
|
||||
"program:"
|
||||
msgid "Too many failed login attempts, try again later."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Login attempt refused, too many failures from %s"
|
||||
msgstr ""
|
||||
"Clave de API erróneo, favor ingresar la clave correcta desde Config->General"
|
||||
" en tu aplicacion externa:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "User logged in to the web interface"
|
||||
msgstr "Usuario conectado a la interfaz web"
|
||||
|
||||
#. Notification
|
||||
#: sabnzbd/interface.py, sabnzbd/notifier.py
|
||||
msgid "User logged in"
|
||||
msgstr "Usuario conectado"
|
||||
msgid "Authentication failed, check username/password."
|
||||
msgstr "Autenticación fallida, compruebe el usuario o la contraseña."
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/interface.py
|
||||
@@ -894,27 +900,21 @@ msgstr ""
|
||||
"El directorio Categoría no puede ser un subdirectorio del directorio de "
|
||||
"descargas temporal."
|
||||
|
||||
#: sabnzbd/interface.py, sabnzbd/skintext.py
|
||||
msgid "ERROR:"
|
||||
msgstr "ERROR:"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Atrás"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/internetspeed.py
|
||||
msgid ""
|
||||
"Internet Bandwidth of IPv4 significantly different from IPv6: %f MB/s versus"
|
||||
" %f MB/s"
|
||||
msgstr ""
|
||||
"El ancho de banda de internet de IPv4 difiere significativamente del de "
|
||||
"IPv6: %f MB/s frente a %f MB/s"
|
||||
|
||||
#. Footer: indicator of warnings
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/skintext.py
|
||||
msgid "Warnings"
|
||||
msgstr "Advertencias"
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py,
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Idle"
|
||||
msgstr "Inactivo"
|
||||
@@ -945,8 +945,8 @@ msgstr "Limitar Velocidad"
|
||||
|
||||
#. Notification - Pause downloading - Four way switch for duplicates -
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtray.py,
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause"
|
||||
msgstr "Pausar"
|
||||
|
||||
@@ -956,8 +956,8 @@ msgid "min"
|
||||
msgstr "mín"
|
||||
|
||||
#. Notification - Resume downloading - Config->Scheduling
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtray.py,
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/notifier.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Resume"
|
||||
msgstr "Reanudar"
|
||||
|
||||
@@ -966,7 +966,7 @@ msgstr "Reanudar"
|
||||
msgid "Scan watched folder"
|
||||
msgstr "Escanear directorio bajo observación"
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Read all RSS feeds"
|
||||
msgstr "Leer todos los canales RSS"
|
||||
|
||||
@@ -978,17 +978,17 @@ msgstr "Carpeta Completa"
|
||||
msgid "Incomplete Folder"
|
||||
msgstr "Carpeta Incompleta"
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraywin.py
|
||||
msgid "Troubleshoot"
|
||||
msgstr "Resolver un problema"
|
||||
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py,
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py,
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Restart"
|
||||
msgstr "Reiniciar"
|
||||
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtray.py
|
||||
#: sabnzbd/macosmenu.py, sabnzbd/sabtraywin.py
|
||||
msgid "Restart without login"
|
||||
msgstr "Reiniciar sin sesión iniciada"
|
||||
|
||||
@@ -1192,6 +1192,12 @@ msgstr "Tratando 7zip con la contraseña \"%s\""
|
||||
msgid "see logfile"
|
||||
msgstr "ver fichero de log"
|
||||
|
||||
#: sabnzbd/newsunpack.py
|
||||
msgid "Unpacking skipped, TAR support requires Python 3.12 or later"
|
||||
msgstr ""
|
||||
"Descompresión omitida, la compatibilidad con TAR requiere Python 3.12 o "
|
||||
"posterior"
|
||||
|
||||
#: sabnzbd/newsunpack.py
|
||||
msgid "Quick Checking"
|
||||
msgstr "Chequeo Rápido"
|
||||
@@ -1368,6 +1374,11 @@ msgstr "Trabajo fallido"
|
||||
msgid "Queue finished"
|
||||
msgstr "Cola terminada"
|
||||
|
||||
#. Notification
|
||||
#: sabnzbd/notifier.py
|
||||
msgid "User logged in"
|
||||
msgstr "Usuario conectado"
|
||||
|
||||
#. Notification
|
||||
#: sabnzbd/notifier.py
|
||||
msgid "Other Messages"
|
||||
@@ -1379,7 +1390,7 @@ msgid "Open folder"
|
||||
msgstr "Abrir carpeta"
|
||||
|
||||
#. Notification action
|
||||
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
#: sabnzbd/notifier.py, sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Open complete folder"
|
||||
msgstr "Abrir todo el folder"
|
||||
|
||||
@@ -1522,7 +1533,8 @@ msgstr "PROPAGANDO %s min"
|
||||
msgid "Downloaded in %s at an average of %sB/s"
|
||||
msgstr "Descargado en %s a una media de %sB/s"
|
||||
|
||||
#. Job details page, file age column header
|
||||
#. Config->RSS filter-type selection menu (e.g. ">3d", "<12h") - Job details
|
||||
#. page, file age column header
|
||||
#: sabnzbd/nzb/object.py, sabnzbd/skintext.py
|
||||
msgid "Age"
|
||||
msgstr "Edad"
|
||||
@@ -1617,6 +1629,23 @@ msgstr ""
|
||||
"Si obtiene este mensaje de error consecutivamente, por favor inténtelo de "
|
||||
"nuevo con otro número.<br>"
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"\n"
|
||||
" SABnzbd is not allowed to use port %s on %s.<br>\n"
|
||||
" Low port numbers are reserved for privileged processes on most systems,\n"
|
||||
" so the port itself is available but cannot be claimed.<br>\n"
|
||||
" <br>\n"
|
||||
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
|
||||
" with a port number of 1024 or higher."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"To keep using the low port, put a reverse proxy in front of SABnzbd "
|
||||
"instead.<br>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"\n"
|
||||
@@ -1705,20 +1734,17 @@ msgstr ""
|
||||
"No es posible vincular al puerto %s en %s. Otro software está utilizando el "
|
||||
"puerto o SABnzbd ya se está ejecutando."
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid ""
|
||||
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
|
||||
msgstr ""
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/panic.py
|
||||
msgid "Cannot launch the browser, probably not found"
|
||||
msgstr ""
|
||||
"Imposible iniciar el navegador, probablemente no se le haya encontrado"
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid "Access denied"
|
||||
msgstr "Acceso denegado"
|
||||
|
||||
#: sabnzbd/panic.py
|
||||
msgid "Error %s: You need to provide a valid username and password."
|
||||
msgstr "Error %s: Necesitas introducir un usuario y contraseña válidos."
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Old queue detected, use Status->Repair to convert the queue"
|
||||
@@ -1849,6 +1875,10 @@ msgstr "No hay un archivo rar anterior correspondiente para %s"
|
||||
msgid "Removing %s failed"
|
||||
msgstr "Error al eliminar %s"
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Removed %s files with unwanted extensions"
|
||||
msgstr ""
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/powersup.py
|
||||
msgid "Failed to hibernate system"
|
||||
@@ -1873,10 +1903,6 @@ msgstr "Se ha recibido una excepción DBus %s"
|
||||
msgid "Empty RSS entry found (%s)"
|
||||
msgstr "Entrada RSS vacía (%s)"
|
||||
|
||||
#: sabnzbd/rss.py
|
||||
msgid "Incompatible feed"
|
||||
msgstr "Canal Incorrecto"
|
||||
|
||||
#. Error message
|
||||
#: sabnzbd/rss.py
|
||||
msgid "Incorrect RSS feed description \"%s\""
|
||||
@@ -1900,50 +1926,15 @@ msgstr "Error al recuperar RSS desde %s: %s"
|
||||
msgid "Server %s uses an untrusted HTTPS certificate"
|
||||
msgstr "El servidor %s utiliza un certificado HTTPS no fiable"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/rss.py
|
||||
msgid "RSS Feed %s was empty"
|
||||
msgstr "El canal RSS %s estaba vacío"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
msgid "Show interface"
|
||||
msgstr "Mostrar interfaz"
|
||||
#: sabnzbd/rss.py
|
||||
msgid "Incompatible feed"
|
||||
msgstr "Canal Incorrecto"
|
||||
|
||||
#. Queue page button or entry box
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for"
|
||||
msgstr "Pausar durante"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 5 minutes"
|
||||
msgstr "Pausar 5 minutos"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 15 minutes"
|
||||
msgstr "Pausar 15 minutos"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 30 minutes"
|
||||
msgstr "Pausar 30 minutos"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 1 hour"
|
||||
msgstr "Pausar 1 hora"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 3 hours"
|
||||
msgstr "Pausar 3 horas"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 6 hours"
|
||||
msgstr "Pausar 6 horas"
|
||||
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py, sabnzbd/skintext.py
|
||||
msgid "Shutdown"
|
||||
msgstr "Apagar"
|
||||
|
||||
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Remaining"
|
||||
msgstr "Restante"
|
||||
|
||||
@@ -1951,6 +1942,44 @@ msgstr "Restante"
|
||||
msgid "Add NZB"
|
||||
msgstr "Añadir NZB"
|
||||
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py
|
||||
msgid "Show interface"
|
||||
msgstr "Mostrar interfaz"
|
||||
|
||||
#. Config->Scheduling
|
||||
#: sabnzbd/sabtraylinux.py, sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Shutdown"
|
||||
msgstr "Apagar"
|
||||
|
||||
#. Queue page button or entry box
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for"
|
||||
msgstr "Pausar durante"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 5 minutes"
|
||||
msgstr "Pausar 5 minutos"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 15 minutes"
|
||||
msgstr "Pausar 15 minutos"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 30 minutes"
|
||||
msgstr "Pausar 30 minutos"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 1 hour"
|
||||
msgstr "Pausar 1 hora"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 3 hours"
|
||||
msgstr "Pausar 3 horas"
|
||||
|
||||
#: sabnzbd/sabtraywin.py, sabnzbd/skintext.py
|
||||
msgid "Pause for 6 hours"
|
||||
msgstr "Pausar 6 horas"
|
||||
|
||||
#. Warning message
|
||||
#: sabnzbd/scheduler.py
|
||||
msgid "Bad schedule %s at %s:%s"
|
||||
@@ -2286,6 +2315,10 @@ msgstr "Equipo"
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Log in"
|
||||
msgstr "Iniciar sesión"
|
||||
@@ -2872,10 +2905,6 @@ msgstr "Puerto en que SABnzbd debería escuchar"
|
||||
msgid "Web Interface Theme"
|
||||
msgstr "Tema de la interfaz web"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Choose a theme."
|
||||
msgstr "Elige un tema."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "SABnzbd Username"
|
||||
msgstr "Usuario SABnzbd"
|
||||
@@ -3026,11 +3055,14 @@ msgstr "Lista de elementos a limpiar"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"List of file extensions that should be deleted after download.<br />For "
|
||||
"example: <b>nfo</b> or <b>nfo, sfv</b>"
|
||||
"List of file extensions, filenames or patterns that should be deleted after "
|
||||
"download.<br />Examples: <b>nfo, sfv</b> (extensions) or <b>thumbs.db</b> "
|
||||
"(filenames) or <b>*.tmp, images/*, */test.jpg</b> (patterns)."
|
||||
msgstr ""
|
||||
"Lista de extensiones de archivo que se deben eliminar después de la descarga"
|
||||
" <br /> Por ejemplo : . <b>nfo</ b> o <b>nfo, sfv < /b>"
|
||||
"Lista de extensiones de archivo, nombres de archivo o patrones que se deben "
|
||||
"eliminar tras la descarga.<br />Ejemplos: <b>nfo, sfv</b> (extensiones) o "
|
||||
"<b>thumbs.db</b> (nombres de archivo) o <b>*.tmp, images/*, */test.jpg</b> "
|
||||
"(patrones)."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "History Retention"
|
||||
@@ -3420,6 +3452,9 @@ msgid ""
|
||||
"all jobs will be marked as Completed and moved to the Complete folder even "
|
||||
"if they are incomplete."
|
||||
msgstr ""
|
||||
"Intentar descomprimir solo los trabajos que pasaron la etapa de "
|
||||
"verificación. Si se desactiva, todos los trabajos se marcarán como "
|
||||
"Completado y se moverán a la carpeta Completa aunque estén incompletos."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Action when encrypted RAR is downloaded"
|
||||
@@ -3515,6 +3550,8 @@ msgstr "Habilitar verificacion basada en SFV"
|
||||
msgid ""
|
||||
"If no par2 files are available, use sfv files (if present) to verify files"
|
||||
msgstr ""
|
||||
"Si no hay archivos par2 disponibles, usar archivos sfv (si existen) para "
|
||||
"verificar los archivos"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "User script can flag job as failed"
|
||||
@@ -3592,8 +3629,10 @@ msgstr ""
|
||||
"nueva."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "The queue will resort every 30 seconds if % downloaded is selected."
|
||||
msgstr "La cola se reordenará cada 30 segundos si se selecciona % descargado."
|
||||
msgid ""
|
||||
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
|
||||
"selected."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Propagation delay"
|
||||
@@ -3737,8 +3776,8 @@ msgid "Naming"
|
||||
msgstr "Nombrado"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "How much can be downloaded this month (K/M/G)"
|
||||
msgstr "Cantidad de descarga permitida este mes (K/M/G)"
|
||||
msgid "How much can be downloaded this Quota period (K/M/G)"
|
||||
msgstr ""
|
||||
|
||||
#. Reset day of the download quota
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3943,7 +3982,7 @@ msgstr "Habilitar"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Articles per request"
|
||||
msgstr ""
|
||||
msgstr "Artículos por solicitud"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
@@ -3951,6 +3990,9 @@ msgid ""
|
||||
"first.<br />This can improve download speeds, especially on connections with"
|
||||
" higher latency."
|
||||
msgstr ""
|
||||
"Solicitar varios artículos por conexión sin esperar primero cada "
|
||||
"respuesta.<br />Esto puede mejorar la velocidad de descarga, especialmente "
|
||||
"en conexiones con mayor latencia."
|
||||
|
||||
#. Button: Remove server
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -4039,10 +4081,6 @@ msgstr "Leer Fuente"
|
||||
msgid "Force Download"
|
||||
msgstr "Forzar Descarga"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Apply filters"
|
||||
msgstr "Aplicar filtros"
|
||||
|
||||
#. Config->RSS edit button
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Edit"
|
||||
@@ -4734,6 +4772,14 @@ msgstr "Eliminar"
|
||||
msgid "Filename"
|
||||
msgstr "Nombre de archivo"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Toggle SABnzbd navigation menu"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Open SABnzbd main menu"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Free Space"
|
||||
msgstr "Espacio libre"
|
||||
@@ -4742,6 +4788,17 @@ msgstr "Espacio libre"
|
||||
msgid "Temp Folder"
|
||||
msgstr "Carpeta temporal"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Clear search"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid ""
|
||||
"Search by name, or refine with filters <code>cat:</code>, "
|
||||
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
|
||||
"<code>my show cat:tv</code>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Multi-Operations"
|
||||
msgstr "Op.Múltiples"
|
||||
@@ -4750,6 +4807,10 @@ msgstr "Op.Múltiples"
|
||||
msgid "Hold shift key to select a range"
|
||||
msgstr "Mantén presionada la tecla shift para seleccionar un rango"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Select job"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Check all"
|
||||
msgstr "Marcar todo"
|
||||
@@ -4784,6 +4845,10 @@ msgstr ""
|
||||
msgid "WARNING:"
|
||||
msgstr "AVISO:"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "ERROR:"
|
||||
msgstr "ERROR:"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Fetch"
|
||||
msgstr "Obtener"
|
||||
@@ -4820,6 +4885,14 @@ msgstr "Columnas adicionales de la cola"
|
||||
msgid "Extra history columns"
|
||||
msgstr "Columnas adicionales del historial"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Progress"
|
||||
msgstr "Progreso"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Actions"
|
||||
msgstr "Acciones"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "page"
|
||||
msgstr "página"
|
||||
@@ -4997,6 +5070,10 @@ msgstr ""
|
||||
msgid "Sort by % downloaded <small>Most→Least</small>"
|
||||
msgstr "Ordenar por % descargado <small>Mayor→Menor</small>"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Sort by Remaining Size <small>Smallest→Largest</small>"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Sort by Age <small>Oldest→Newest</small>"
|
||||
msgstr "Ordenar por Fecha <small>Más viejo→Más nuevo</small>"
|
||||
|
||||
Loaded 100 of 295 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user