mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2026-03-05 13:40:08 -05:00
Compare commits
36 Commits
v1.25.2.47
...
v1.26.0.48
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94f439e238 | ||
|
|
903a88c121 | ||
|
|
9690ab6883 | ||
|
|
1e1a2b3b4a | ||
|
|
9dc2d3669c | ||
|
|
511c76e219 | ||
|
|
78329b7b92 | ||
|
|
4240048853 | ||
|
|
432af42ffd | ||
|
|
0d6c03f8d4 | ||
|
|
96830f975e | ||
|
|
13c538ff58 | ||
|
|
14250e9634 | ||
|
|
e2f7890d76 | ||
|
|
257d38de66 | ||
|
|
fd2a14e01b | ||
|
|
b4d76c7138 | ||
|
|
9655f37fa8 | ||
|
|
246fb9b855 | ||
|
|
25afadc9b2 | ||
|
|
3f547f0856 | ||
|
|
11e322b6d7 | ||
|
|
02ff133a62 | ||
|
|
47268aac87 | ||
|
|
8aad1ac554 | ||
|
|
9037cde439 | ||
|
|
2afafd79e4 | ||
|
|
f4fa2517d2 | ||
|
|
37bc46c1cd | ||
|
|
3e3a7ed4f0 | ||
|
|
04fa7d366d | ||
|
|
ed9a3214a2 | ||
|
|
66a9e1a653 | ||
|
|
8cb59c35fb | ||
|
|
94e9c05d60 | ||
|
|
8d2c4e1246 |
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-1.3318" y1="43.7371" x2="67.0419" y2="26.0967">
|
||||
<stop offset="0.1237" style="stop-color:#7866FF"/>
|
||||
<stop offset="0.5376" style="stop-color:#FE2EB6"/>
|
||||
<stop offset="0.8548" style="stop-color:#FD0486"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_1_);" points="67.3,16 43.7,0 0,31.1 11.1,70 58.9,60.3 "/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="45.9148" y1="38.9098" x2="67.6577" y2="9.0989">
|
||||
<stop offset="0.1237" style="stop-color:#FF0080"/>
|
||||
<stop offset="0.2587" style="stop-color:#FE0385"/>
|
||||
<stop offset="0.4109" style="stop-color:#FA0C92"/>
|
||||
<stop offset="0.5713" style="stop-color:#F41BA9"/>
|
||||
<stop offset="0.7363" style="stop-color:#EB2FC8"/>
|
||||
<stop offset="0.8656" style="stop-color:#E343E6"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_2_);" points="67.3,16 43.7,0 38,15.7 38,47.8 70,47.8 "/>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="13.4" y="13.4" style="fill:#000000;" width="43.2" height="43.2"/>
|
||||
<rect x="17.4" y="48.5" style="fill:#FFFFFF;" width="16.2" height="2.7"/>
|
||||
<g>
|
||||
<path style="fill:#FFFFFF;" d="M17.4,19.1h6.9c5.6,0,9.5,3.8,9.5,8.9V28c0,5-3.9,8.9-9.5,8.9h-6.9V19.1z M21.4,22.7v10.7h3
|
||||
c3.2,0,5.4-2.2,5.4-5.3V28c0-3.2-2.2-5.4-5.4-5.4H21.4z"/>
|
||||
<polygon style="fill:#FFFFFF;" points="40.3,22.7 34.9,22.7 34.9,19.1 49.6,19.1 49.6,22.7 44.2,22.7 44.2,37 40.3,37 "/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,66 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="120.1px" height="130.2px" viewBox="0 0 120.1 130.2" style="enable-background:new 0 0 120.1 130.2;" xml:space="preserve"
|
||||
>
|
||||
<g>
|
||||
<linearGradient id="XMLID_2_" gradientUnits="userSpaceOnUse" x1="31.8412" y1="120.5578" x2="110.2402" y2="73.24">
|
||||
<stop offset="0" style="stop-color:#FCEE39"/>
|
||||
<stop offset="1" style="stop-color:#F37B3D"/>
|
||||
</linearGradient>
|
||||
<path id="XMLID_3041_" style="fill:url(#XMLID_2_);" d="M118.6,71.8c0.9-0.8,1.4-1.9,1.5-3.2c0.1-2.6-1.8-4.7-4.4-4.9
|
||||
c-1.2-0.1-2.4,0.4-3.3,1.1l0,0l-83.8,45.9c-1.9,0.8-3.6,2.2-4.7,4.1c-2.9,4.8-1.3,11,3.6,13.9c3.4,2,7.5,1.8,10.7-0.2l0,0l0,0
|
||||
c0.2-0.2,0.5-0.3,0.7-0.5l78-54.8C117.3,72.9,118.4,72.1,118.6,71.8L118.6,71.8L118.6,71.8z"/>
|
||||
<linearGradient id="XMLID_3_" gradientUnits="userSpaceOnUse" x1="48.3607" y1="6.9083" x2="119.9179" y2="69.5546">
|
||||
<stop offset="0" style="stop-color:#EF5A6B"/>
|
||||
<stop offset="0.57" style="stop-color:#F26F4E"/>
|
||||
<stop offset="1" style="stop-color:#F37B3D"/>
|
||||
</linearGradient>
|
||||
<path id="XMLID_3049_" style="fill:url(#XMLID_3_);" d="M118.8,65.1L118.8,65.1L55,2.5C53.6,1,51.6,0,49.3,0
|
||||
c-4.3,0-7.7,3.5-7.7,7.7v0c0,2.1,0.8,3.9,2.1,5.3l0,0l0,0c0.4,0.4,0.8,0.7,1.2,1l67.4,57.7l0,0c0.8,0.7,1.8,1.2,3,1.3
|
||||
c2.6,0.1,4.7-1.8,4.9-4.4C120.2,67.3,119.7,66,118.8,65.1z"/>
|
||||
<linearGradient id="XMLID_4_" gradientUnits="userSpaceOnUse" x1="52.9467" y1="63.6407" x2="10.5379" y2="37.1562">
|
||||
<stop offset="0" style="stop-color:#7C59A4"/>
|
||||
<stop offset="0.3852" style="stop-color:#AF4C92"/>
|
||||
<stop offset="0.7654" style="stop-color:#DC4183"/>
|
||||
<stop offset="0.957" style="stop-color:#ED3D7D"/>
|
||||
</linearGradient>
|
||||
<path id="XMLID_3042_" style="fill:url(#XMLID_4_);" d="M57.1,59.5C57,59.5,17.7,28.5,16.9,28l0,0l0,0c-0.6-0.3-1.2-0.6-1.8-0.9
|
||||
c-5.8-2.2-12.2,0.8-14.4,6.6c-1.9,5.1,0.2,10.7,4.6,13.4l0,0l0,0C6,47.5,6.6,47.8,7.3,48c0.4,0.2,45.4,18.8,45.4,18.8l0,0
|
||||
c1.8,0.8,3.9,0.3,5.1-1.2C59.3,63.7,59,61,57.1,59.5z"/>
|
||||
<linearGradient id="XMLID_5_" gradientUnits="userSpaceOnUse" x1="52.1736" y1="3.7019" x2="10.7706" y2="37.8971">
|
||||
<stop offset="0" style="stop-color:#EF5A6B"/>
|
||||
<stop offset="0.364" style="stop-color:#EE4E72"/>
|
||||
<stop offset="1" style="stop-color:#ED3D7D"/>
|
||||
</linearGradient>
|
||||
<path id="XMLID_3057_" style="fill:url(#XMLID_5_);" d="M49.3,0c-1.7,0-3.3,0.6-4.6,1.5L4.9,28.3c-0.1,0.1-0.2,0.1-0.2,0.2l-0.1,0
|
||||
l0,0c-1.7,1.2-3.1,3-3.9,5.1C-1.5,39.4,1.5,45.9,7.3,48c3.6,1.4,7.5,0.7,10.4-1.4l0,0l0,0c0.7-0.5,1.3-1,1.8-1.6l34.6-31.2l0,0
|
||||
c1.8-1.4,3-3.6,3-6.1v0C57.1,3.5,53.6,0,49.3,0z"/>
|
||||
<g id="XMLID_3008_">
|
||||
<rect id="XMLID_3033_" x="34.6" y="37.4" style="fill:#000000;" width="51" height="51"/>
|
||||
<rect id="XMLID_3032_" x="39" y="78.8" style="fill:#FFFFFF;" width="19.1" height="3.2"/>
|
||||
<g id="XMLID_3009_">
|
||||
<path id="XMLID_3030_" style="fill:#FFFFFF;" d="M38.8,50.8l1.5-1.4c0.4,0.5,0.8,0.8,1.3,0.8c0.6,0,0.9-0.4,0.9-1.2l0-5.3l2.3,0
|
||||
l0,5.3c0,1-0.3,1.8-0.8,2.3c-0.5,0.5-1.3,0.8-2.3,0.8C40.2,52.2,39.4,51.6,38.8,50.8z"/>
|
||||
<path id="XMLID_3028_" style="fill:#FFFFFF;" d="M45.3,43.8l6.7,0v1.9l-4.4,0V47l4,0l0,1.8l-4,0l0,1.3l4.5,0l0,2l-6.7,0
|
||||
L45.3,43.8z"/>
|
||||
<path id="XMLID_3026_" style="fill:#FFFFFF;" d="M55,45.8l-2.5,0l0-2l7.3,0l0,2l-2.5,0l0,6.3l-2.3,0L55,45.8z"/>
|
||||
<path id="XMLID_3022_" style="fill:#FFFFFF;" d="M39,54l4.3,0c1,0,1.8,0.3,2.3,0.7c0.3,0.3,0.5,0.8,0.5,1.4v0
|
||||
c0,1-0.5,1.5-1.3,1.9c1,0.3,1.6,0.9,1.6,2v0c0,1.4-1.2,2.3-3.1,2.3l-4.3,0L39,54z M43.8,56.6c0-0.5-0.4-0.7-1-0.7l-1.5,0l0,1.5
|
||||
l1.4,0C43.4,57.3,43.8,57.1,43.8,56.6L43.8,56.6z M43,59l-1.8,0l0,1.5H43c0.7,0,1.1-0.3,1.1-0.8v0C44.1,59.2,43.7,59,43,59z"/>
|
||||
<path id="XMLID_3019_" style="fill:#FFFFFF;" d="M46.8,54l3.9,0c1.3,0,2.1,0.3,2.7,0.9c0.5,0.5,0.7,1.1,0.7,1.9v0
|
||||
c0,1.3-0.7,2.1-1.7,2.6l2,2.9l-2.6,0l-1.7-2.5h-1l0,2.5l-2.3,0L46.8,54z M50.6,58c0.8,0,1.2-0.4,1.2-1v0c0-0.7-0.5-1-1.2-1
|
||||
l-1.5,0v2H50.6z"/>
|
||||
<path id="XMLID_3016_" style="fill:#FFFFFF;" d="M56.8,54l2.2,0l3.5,8.4l-2.5,0l-0.6-1.5l-3.2,0l-0.6,1.5l-2.4,0L56.8,54z
|
||||
M58.8,59l-0.9-2.3L57,59L58.8,59z"/>
|
||||
<path id="XMLID_3014_" style="fill:#FFFFFF;" d="M62.8,54l2.3,0l0,8.3l-2.3,0L62.8,54z"/>
|
||||
<path id="XMLID_3012_" style="fill:#FFFFFF;" d="M65.7,54l2.1,0l3.4,4.4l0-4.4l2.3,0l0,8.3l-2,0L68,57.8l0,4.6l-2.3,0L65.7,54z"
|
||||
/>
|
||||
<path id="XMLID_3010_" style="fill:#FFFFFF;" d="M73.7,61.1l1.3-1.5c0.8,0.7,1.7,1,2.7,1c0.6,0,1-0.2,1-0.6v0
|
||||
c0-0.4-0.3-0.5-1.4-0.8c-1.8-0.4-3.1-0.9-3.1-2.6v0c0-1.5,1.2-2.7,3.2-2.7c1.4,0,2.5,0.4,3.4,1.1l-1.2,1.6
|
||||
c-0.8-0.5-1.6-0.8-2.3-0.8c-0.6,0-0.8,0.2-0.8,0.5v0c0,0.4,0.3,0.5,1.4,0.8c1.9,0.4,3.1,1,3.1,2.6v0c0,1.7-1.3,2.7-3.4,2.7
|
||||
C76.1,62.5,74.7,62,73.7,61.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.8 KiB |
@@ -1,50 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="22.9451" y1="75.7869" x2="74.7868" y2="20.6415">
|
||||
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
|
||||
<stop offset="0.4044" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.4677" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.6505" style="stop-color:#EB8523"/>
|
||||
<stop offset="0.9516" style="stop-color:#FEBD11"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_1_);" points="49.8,15.2 36,36.7 58.4,70 70,23.1 "/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="17.7187" y1="73.2922" x2="69.5556" y2="18.1519">
|
||||
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
|
||||
<stop offset="0.4044" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.4677" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.7043" style="stop-color:#EB8523"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_2_);" points="51.1,15.7 49,0 18.8,33.6 27.6,42.3 20.8,70 58.4,70 "/>
|
||||
</g>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="1.8281" y1="53.4275" x2="48.8245" y2="9.2255">
|
||||
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
|
||||
<stop offset="0.6613" style="stop-color:#C41E57"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_3_);" points="49,0 11.6,0 0,47.1 55.6,47.1 "/>
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="49.8935" y1="-11.5569" x2="48.8588" y2="24.0352">
|
||||
<stop offset="0.5" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.6668" style="stop-color:#D13F48"/>
|
||||
<stop offset="0.7952" style="stop-color:#D94F39"/>
|
||||
<stop offset="0.8656" style="stop-color:#DD5433"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_4_);" points="55.3,47.1 51.1,15.7 49,0 41.7,23 "/>
|
||||
</g>
|
||||
<g>
|
||||
|
||||
<rect x="13.4" y="13.5" transform="matrix(-1 2.577289e-003 -2.577289e-003 -1 70.0288 70.081)" style="fill:#000000;" width="43.2" height="43.2"/>
|
||||
|
||||
<rect x="17.6" y="48.6" transform="matrix(1 -2.577289e-003 2.577289e-003 1 -0.1287 6.634109e-002)" style="fill:#FFFFFF;" width="16.2" height="2.7"/>
|
||||
<path style="fill:#FFFFFF;" d="M17.4,19.1l8.2,0c2.3,0,4,0.6,5.2,1.8c1,1,1.5,2.4,1.5,4.1l0,0.1c0,1.5-0.3,2.6-1.1,3.5
|
||||
c-0.7,0.9-1.6,1.6-2.8,2l4.4,6.4l-4.6,0l-3.7-5.5l-3.3,0l0,5.5l-3.9,0L17.4,19.1z M25.3,27.8c1,0,1.7-0.2,2.2-0.7
|
||||
c0.5-0.5,0.8-1.1,0.8-1.8l0-0.1c0-0.9-0.3-1.5-0.8-1.9c-0.5-0.4-1.3-0.6-2.3-0.6l-3.9,0l0,5.1L25.3,27.8z"/>
|
||||
<path style="fill:#FFFFFF;" d="M36,33.2l-1.9,0l0-3.3l2.5,0l0.6-3.8l-2.3,0l0-3.3l2.8,0l0.6-3.7l3.4,0l-0.6,3.7l3.7,0l0.6-3.7
|
||||
l3.4,0l-0.6,3.7l1.9,0l0,3.3l-2.5,0L47,29.9l2.3,0l0,3.3l-2.8,0L45.8,37l-3.4,0l0.7-3.8l-3.7,0L38.7,37l-3.4,0L36,33.2z
|
||||
M43.7,29.9l0.6-3.8l-3.7,0L40,29.9L43.7,29.9z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.1 KiB |
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" x1="70.22612" y1="27.79912" x2="-5.13024" y2="63.12242" gradientTransform="matrix(1, 0, 0, -1, 0, 71.27997)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#c90f5e"/>
|
||||
<stop offset="0.22111" stop-color="#c90f5e"/>
|
||||
<stop offset="0.2356" stop-color="#c90f5e"/>
|
||||
<stop offset="0.35559" stop-color="#ca135c"/>
|
||||
<stop offset="0.46633" stop-color="#ce1e57"/>
|
||||
<stop offset="0.5735" stop-color="#d4314e"/>
|
||||
<stop offset="0.67844" stop-color="#dc4b41"/>
|
||||
<stop offset="0.78179" stop-color="#e66d31"/>
|
||||
<stop offset="0.88253" stop-color="#f3961d"/>
|
||||
<stop offset="0.94241" stop-color="#fcb20f"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="24.65904" y1="61.99608" x2="46.04762" y2="2.93445" gradientTransform="matrix(1, 0, 0, -1, 0, 71.27997)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.04188" stop-color="#077cfb"/>
|
||||
<stop offset="0.44503" stop-color="#c90f5e"/>
|
||||
<stop offset="0.95812" stop-color="#077cfb"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-3" x1="17.39552" y1="63.34592" x2="33.19389" y2="7.20092" gradientTransform="matrix(1, 0, 0, -1, 0, 71.27997)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.27749" stop-color="#c90f5e"/>
|
||||
<stop offset="0.97382" stop-color="#fcb20f"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>rider</title>
|
||||
<g>
|
||||
<polygon points="70 27.237 63.391 23.75 20.926 0 3.827 17.921 21.619 41.068 60.537 44.397 70 27.237" fill="url(#linear-gradient)"/>
|
||||
<polygon points="50.423 16.132 44.271 1.107 27.643 17.471 11.768 50.194 49.411 70 70 57.98 50.423 16.132" fill="url(#linear-gradient-2)"/>
|
||||
<polygon points="20.926 0 0 14.095 7.779 62.172 27.848 69.889 53.78 48.823 20.926 0" fill="url(#linear-gradient-3)"/>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="13.30219" y="13.19311" width="43.61371" height="43.61371"/>
|
||||
<g>
|
||||
<path d="M17.22741,18.86293h8.39564a7.38416,7.38416,0,0,1,5.34268,1.85358,5.86989,5.86989,0,0,1,1.52648,4.1433h0A5.74339,5.74339,0,0,1,28.567,30.5296l4.47041,6.54206H28.34891L24.42368,31.1838h-3.162v5.88785H17.22741V18.86293h0ZM25.296,27.69471c1.96262,0,3.053-1.09034,3.053-2.61682h0c0-1.74455-1.19938-2.61682-3.162-2.61682H21.15265v5.23365H25.296Z" fill="#fff"/>
|
||||
<path d="M36.09034,18.86293H43.2866c5.77882,0,9.70405,3.92523,9.70405,9.15888h0c0,5.12461-3.92523,9.15888-9.70405,9.15888H36.09034V18.86293Zm4.03427,3.59813V33.47352h3.162a5.23727,5.23727,0,0,0,5.56075-5.45171h0a5.26493,5.26493,0,0,0-5.56075-5.56075h-3.162Z" fill="#fff"/>
|
||||
</g>
|
||||
<rect x="17.22741" y="48.62925" width="16.35514" height="2.72586" fill="#fff"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.0 KiB |
@@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="25.0676" y1="1.4599" x2="43.1829" y2="66.675">
|
||||
<stop offset="0.2849" style="stop-color:#00CDD7"/>
|
||||
<stop offset="0.9409" style="stop-color:#2086D7"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_1_);" points="9.4,63.3 0,7.3 17.5,0.1 28.6,6.7 38.8,1.2 60.1,9.4 48.1,70 "/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="30.7199" y1="9.7343" x2="61.365" y2="54.6713">
|
||||
<stop offset="0.1398" style="stop-color:#FFF045"/>
|
||||
<stop offset="0.3656" style="stop-color:#00CDD7"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_2_);" points="70,23.7 61,1.4 44.6,0 19.3,24.3 26.1,55.6 38.8,64.6 70,46 62.3,31.7 "/>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="61.0819" y1="15.2899" x2="65.1065" y2="29.5436">
|
||||
<stop offset="0.2849" style="stop-color:#00CDD7"/>
|
||||
<stop offset="0.9409" style="stop-color:#2086D7"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_3_);" points="56,20.4 62.3,31.7 70,23.7 64.4,9.8 "/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<rect x="13.4" y="13.4" style="fill:#000000;" width="43.2" height="43.2"/>
|
||||
<rect x="17.5" y="48.5" style="fill:#FFFFFF;" width="16.2" height="2.7"/>
|
||||
<path style="fill:#FFFFFF;" d="M38.7,34.3l2.3-2.8c1.6,1.3,3.3,2.2,5.3,2.2c1.6,0,2.5-0.6,2.5-1.7v-0.1c0-1-0.6-1.5-3.6-2.3
|
||||
c-3.6-0.9-5.8-1.9-5.8-5.5v-0.1c0-3.3,2.6-5.4,6.2-5.4c2.6,0,4.8,0.8,6.6,2.3l-2,3c-1.6-1.1-3.1-1.8-4.6-1.8
|
||||
c-1.5,0-2.3,0.7-2.3,1.6v0.1c0,1.2,0.8,1.6,3.8,2.4c3.6,1,5.6,2.3,5.6,5.4v0.1c0,3.6-2.7,5.6-6.5,5.6
|
||||
C43.5,37.2,40.8,36.2,38.7,34.3"/>
|
||||
</g>
|
||||
<polygon style="fill:#FFFFFF;" points="35.2,19 32.5,29.4 29.5,19 26.5,19 23.4,29.4 20.7,19 16.6,19 21.7,36.9 25,36.9 28,26.5
|
||||
30.9,36.9 34.3,36.9 39.4,19 "/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.1 KiB |
12
README.md
12
README.md
@@ -68,16 +68,16 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
|
||||
|
||||
## JetBrains
|
||||
|
||||
Thank you to [<img src="/Logo/jetbrains.svg" alt="JetBrains" width="32"> JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools.
|
||||
Thank you to [<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.png" alt="JetBrains" width="96">](http://www.jetbrains.com/) for providing us with free licenses to their great tools.
|
||||
|
||||
- [<img src="/Logo/resharper.svg" alt="ReSharper" width="32"> ReSharper](http://www.jetbrains.com/resharper/)
|
||||
- [<img src="/Logo/webstorm.svg" alt="WebStorm" width="32"> WebStorm](http://www.jetbrains.com/webstorm/)
|
||||
- [<img src="/Logo/rider.svg" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/)
|
||||
- [<img src="/Logo/dottrace.svg" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/)
|
||||
* [<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/ReSharper_icon.png" alt="ReSharper" width="32"> ReSharper](http://www.jetbrains.com/resharper/)
|
||||
* [<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/WebStorm_icon.png" alt="WebStorm" width="32"> WebStorm](http://www.jetbrains.com/webstorm/)
|
||||
* [<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/Rider_icon.png" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/)
|
||||
* [<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/dotTrace_icon.png" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/)
|
||||
|
||||
### License
|
||||
|
||||
- [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
|
||||
- Copyright 2010-2022
|
||||
- Copyright 2010-2024
|
||||
|
||||
Icon Credit - [Box vector created by freepik - www.freepik.com](https://www.freepik.com/vectors/box)
|
||||
|
||||
@@ -9,13 +9,13 @@ variables:
|
||||
testsFolder: './_tests'
|
||||
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
|
||||
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
|
||||
majorVersion: '1.25.2'
|
||||
majorVersion: '1.26.0'
|
||||
minorVersion: $[counter('minorVersion', 1)]
|
||||
prowlarrVersion: '$(majorVersion).$(minorVersion)'
|
||||
buildName: '$(Build.SourceBranchName).$(prowlarrVersion)'
|
||||
sentryOrg: 'servarr'
|
||||
sentryUrl: 'https://sentry.servarr.com'
|
||||
dotnetVersion: '6.0.424'
|
||||
dotnetVersion: '6.0.427'
|
||||
nodeVersion: '20.X'
|
||||
innoVersion: '6.2.2'
|
||||
windowsImage: 'windows-2022'
|
||||
|
||||
@@ -20,7 +20,7 @@ import LogsTableConnector from 'System/Events/LogsTableConnector';
|
||||
import Logs from 'System/Logs/Logs';
|
||||
import Status from 'System/Status/Status';
|
||||
import Tasks from 'System/Tasks/Tasks';
|
||||
import UpdatesConnector from 'System/Updates/UpdatesConnector';
|
||||
import Updates from 'System/Updates/Updates';
|
||||
import getPathWithUrlBase from 'Utilities/getPathWithUrlBase';
|
||||
|
||||
function RedirectWithUrlBase() {
|
||||
@@ -99,7 +99,7 @@ function AppRoutes() {
|
||||
|
||||
<Route path="/system/backup" component={BackupsConnector} />
|
||||
|
||||
<Route path="/system/updates" component={UpdatesConnector} />
|
||||
<Route path="/system/updates" component={Updates} />
|
||||
|
||||
<Route path="/system/events" component={LogsTableConnector} />
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ import { IndexerCategory } from 'Indexer/Indexer';
|
||||
import Application from 'typings/Application';
|
||||
import DownloadClient from 'typings/DownloadClient';
|
||||
import Notification from 'typings/Notification';
|
||||
import { UiSettings } from 'typings/UiSettings';
|
||||
import General from 'typings/Settings/General';
|
||||
import UiSettings from 'typings/Settings/UiSettings';
|
||||
|
||||
export interface AppProfileAppState
|
||||
extends AppSectionState<Application>,
|
||||
@@ -28,6 +29,10 @@ export interface DownloadClientAppState
|
||||
isTestingAll: boolean;
|
||||
}
|
||||
|
||||
export interface GeneralAppState
|
||||
extends AppSectionItemState<General>,
|
||||
AppSectionSaveState {}
|
||||
|
||||
export interface IndexerCategoryAppState
|
||||
extends AppSectionState<IndexerCategory>,
|
||||
AppSectionDeleteState,
|
||||
@@ -43,6 +48,7 @@ interface SettingsAppState {
|
||||
appProfiles: AppProfileAppState;
|
||||
applications: ApplicationAppState;
|
||||
downloadClients: DownloadClientAppState;
|
||||
general: GeneralAppState;
|
||||
indexerCategories: IndexerCategoryAppState;
|
||||
notifications: NotificationAppState;
|
||||
ui: UiSettingsAppState;
|
||||
|
||||
@@ -141,6 +141,16 @@ class SignalRConnector extends Component {
|
||||
console.error(`signalR: Unable to find handler for ${name}`);
|
||||
};
|
||||
|
||||
handleApplications = ({ action, resource }) => {
|
||||
const section = 'settings.applications';
|
||||
|
||||
if (action === 'created' || action === 'updated') {
|
||||
this.props.dispatchUpdateItem({ section, ...resource });
|
||||
} else if (action === 'deleted') {
|
||||
this.props.dispatchRemoveItem({ section, id: resource.id });
|
||||
}
|
||||
};
|
||||
|
||||
handleCommand = (body) => {
|
||||
if (body.action === 'sync') {
|
||||
this.props.dispatchFetchCommands();
|
||||
@@ -150,8 +160,8 @@ class SignalRConnector extends Component {
|
||||
const resource = body.resource;
|
||||
const status = resource.status;
|
||||
|
||||
// Both sucessful and failed commands need to be
|
||||
// completed, otherwise they spin until they timeout.
|
||||
// Both successful and failed commands need to be
|
||||
// completed, otherwise they spin until they time out.
|
||||
|
||||
if (status === 'completed' || status === 'failed') {
|
||||
this.props.dispatchFinishCommand(resource);
|
||||
@@ -160,6 +170,16 @@ class SignalRConnector extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
handleDownloadclient = ({ action, resource }) => {
|
||||
const section = 'settings.downloadClients';
|
||||
|
||||
if (action === 'created' || action === 'updated') {
|
||||
this.props.dispatchUpdateItem({ section, ...resource });
|
||||
} else if (action === 'deleted') {
|
||||
this.props.dispatchRemoveItem({ section, id: resource.id });
|
||||
}
|
||||
};
|
||||
|
||||
handleHealth = () => {
|
||||
this.props.dispatchFetchHealth();
|
||||
};
|
||||
@@ -168,14 +188,33 @@ class SignalRConnector extends Component {
|
||||
this.props.dispatchFetchIndexerStatus();
|
||||
};
|
||||
|
||||
handleIndexer = (body) => {
|
||||
const action = body.action;
|
||||
handleIndexer = ({ action, resource }) => {
|
||||
const section = 'indexers';
|
||||
|
||||
if (action === 'updated') {
|
||||
this.props.dispatchUpdateItem({ section, ...body.resource });
|
||||
if (action === 'created' || action === 'updated') {
|
||||
this.props.dispatchUpdateItem({ section, ...resource });
|
||||
} else if (action === 'deleted') {
|
||||
this.props.dispatchRemoveItem({ section, id: body.resource.id });
|
||||
this.props.dispatchRemoveItem({ section, id: resource.id });
|
||||
}
|
||||
};
|
||||
|
||||
handleIndexerproxy = ({ action, resource }) => {
|
||||
const section = 'settings.indexerProxies';
|
||||
|
||||
if (action === 'created' || action === 'updated') {
|
||||
this.props.dispatchUpdateItem({ section, ...resource });
|
||||
} else if (action === 'deleted') {
|
||||
this.props.dispatchRemoveItem({ section, id: resource.id });
|
||||
}
|
||||
};
|
||||
|
||||
handleNotification = ({ action, resource }) => {
|
||||
const section = 'settings.notifications';
|
||||
|
||||
if (action === 'created' || action === 'updated') {
|
||||
this.props.dispatchUpdateItem({ section, ...resource });
|
||||
} else if (action === 'deleted') {
|
||||
this.props.dispatchRemoveItem({ section, id: resource.id });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -4,11 +4,13 @@ import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { fetchApplications, fetchIndexerProxies, fetchNotifications } from 'Store/Actions/settingsActions';
|
||||
import { fetchTagDetails, fetchTags } from 'Store/Actions/tagActions';
|
||||
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
|
||||
import sortByProp from 'Utilities/Array/sortByProp';
|
||||
import Tags from './Tags';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.tags,
|
||||
createSortedSectionSelector('tags', sortByProp('label')),
|
||||
(tags) => {
|
||||
const isFetching = tags.isFetching || tags.details.isFetching;
|
||||
const error = tags.error || tags.details.error;
|
||||
|
||||
@@ -116,6 +116,7 @@ class BackupRow extends Component {
|
||||
|
||||
<TableRowCell className={styles.actions}>
|
||||
<IconButton
|
||||
title={translate('RestoreBackup')}
|
||||
name={icons.RESTORE}
|
||||
onPress={this.onRestorePress}
|
||||
/>
|
||||
@@ -138,7 +139,9 @@ class BackupRow extends Component {
|
||||
isOpen={isConfirmDeleteModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title={translate('DeleteBackup')}
|
||||
message={translate('DeleteBackupMessageText', { name })}
|
||||
message={translate('DeleteBackupMessageText', {
|
||||
name
|
||||
})}
|
||||
confirmLabel={translate('Delete')}
|
||||
onConfirm={this.onConfirmDeletePress}
|
||||
onCancel={this.onConfirmDeleteModalClose}
|
||||
|
||||
@@ -109,7 +109,7 @@ class Backups extends Component {
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadBackups')}
|
||||
{translate('BackupsLoadError')}
|
||||
</Alert>
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import styles from './RestoreBackupModalContent.css';
|
||||
|
||||
function getErrorMessage(error) {
|
||||
if (!error || !error.responseJSON || !error.responseJSON.message) {
|
||||
return 'Error restoring backup';
|
||||
return translate('ErrorRestoringBackup');
|
||||
}
|
||||
|
||||
return error.responseJSON.message;
|
||||
@@ -146,7 +146,9 @@ class RestoreBackupModalContent extends Component {
|
||||
|
||||
<ModalBody>
|
||||
{
|
||||
!!id && `Would you like to restore the backup '${name}'?`
|
||||
!!id && translate('WouldYouLikeToRestoreBackup', {
|
||||
name
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
@@ -203,7 +205,7 @@ class RestoreBackupModalContent extends Component {
|
||||
|
||||
<ModalFooter>
|
||||
<div className={styles.additionalInfo}>
|
||||
Note: Prowlarr will automatically restart and reload the UI during the restore process.
|
||||
{translate('RestartReloadNote')}
|
||||
</div>
|
||||
|
||||
<Button onPress={onModalClose}>
|
||||
@@ -216,7 +218,7 @@ class RestoreBackupModalContent extends Component {
|
||||
isSpinning={isRestoring}
|
||||
onPress={this.onRestorePress}
|
||||
>
|
||||
Restore
|
||||
{translate('Restore')}
|
||||
</SpinnerButton>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
|
||||
@@ -84,7 +84,7 @@ function LogsTable(props) {
|
||||
{
|
||||
isPopulated && !error && !items.length &&
|
||||
<Alert kind={kinds.INFO}>
|
||||
No events found
|
||||
{translate('NoEventsFound')}
|
||||
</Alert>
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ function LogsTableDetailsModal(props) {
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<ModalHeader>
|
||||
Details
|
||||
{translate('Details')}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import Link from 'Components/Link/Link';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
||||
@@ -77,13 +77,15 @@ class LogFiles extends Component {
|
||||
<PageContentBody>
|
||||
<Alert>
|
||||
<div>
|
||||
Log files are located in: {location}
|
||||
{translate('LogFilesLocation', {
|
||||
location
|
||||
})}
|
||||
</div>
|
||||
|
||||
{
|
||||
currentLogView === 'Log Files' &&
|
||||
<div>
|
||||
The log level defaults to 'Info' and can be changed in <Link to="/settings/general">General Settings</Link>
|
||||
<InlineMarkdown data={translate('TheLogLevelDefault')} />
|
||||
</div>
|
||||
}
|
||||
</Alert>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import { fetchLogFiles } from 'Store/Actions/systemActions';
|
||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||
import combinePath from 'Utilities/String/combinePath';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import LogFiles from './LogFiles';
|
||||
|
||||
function createMapStateToProps() {
|
||||
@@ -29,7 +30,7 @@ function createMapStateToProps() {
|
||||
isFetching,
|
||||
items,
|
||||
deleteFilesExecuting,
|
||||
currentLogView: 'Log Files',
|
||||
currentLogView: translate('LogFiles'),
|
||||
location: combinePath(isWindows, appData, ['logs'])
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import Link from 'Components/Link/Link';
|
||||
import RelativeDateCell from 'Components/Table/Cells/RelativeDateCell';
|
||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './LogFilesTableRow.css';
|
||||
|
||||
class LogFilesTableRow extends Component {
|
||||
@@ -32,7 +33,7 @@ class LogFilesTableRow extends Component {
|
||||
target="_blank"
|
||||
noRouter={true}
|
||||
>
|
||||
Download
|
||||
{translate('Download')}
|
||||
</Link>
|
||||
</TableRowCell>
|
||||
</TableRow>
|
||||
|
||||
@@ -4,6 +4,7 @@ import Menu from 'Components/Menu/Menu';
|
||||
import MenuButton from 'Components/Menu/MenuButton';
|
||||
import MenuContent from 'Components/Menu/MenuContent';
|
||||
import MenuItem from 'Components/Menu/MenuItem';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
class LogsNavMenu extends Component {
|
||||
|
||||
@@ -50,13 +51,13 @@ class LogsNavMenu extends Component {
|
||||
<MenuItem
|
||||
to={'/system/logs/files'}
|
||||
>
|
||||
Log Files
|
||||
{translate('LogFiles')}
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem
|
||||
to={'/system/logs/files/update'}
|
||||
>
|
||||
Updater Log Files
|
||||
{translate('UpdaterLogFiles')}
|
||||
</MenuItem>
|
||||
</MenuContent>
|
||||
</Menu>
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
|
||||
import styles from './UpdateChanges.css';
|
||||
|
||||
class UpdateChanges extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
title,
|
||||
changes
|
||||
} = this.props;
|
||||
|
||||
if (changes.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const uniqueChanges = [...new Set(changes)];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.title}>{title}</div>
|
||||
<ul>
|
||||
{
|
||||
uniqueChanges.map((change, index) => {
|
||||
const checkChange = change.replace(/#\d{3,5}\b/g, (match, contents) => {
|
||||
return `[${match}](https://github.com/Prowlarr/Prowlarr/issues/${match.substring(1)})`;
|
||||
});
|
||||
|
||||
return (
|
||||
<li key={index}>
|
||||
<InlineMarkdown data={checkChange} />
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
UpdateChanges.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
changes: PropTypes.arrayOf(PropTypes.string)
|
||||
};
|
||||
|
||||
export default UpdateChanges;
|
||||
43
frontend/src/System/Updates/UpdateChanges.tsx
Normal file
43
frontend/src/System/Updates/UpdateChanges.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
|
||||
import styles from './UpdateChanges.css';
|
||||
|
||||
interface UpdateChangesProps {
|
||||
title: string;
|
||||
changes: string[];
|
||||
}
|
||||
|
||||
function UpdateChanges(props: UpdateChangesProps) {
|
||||
const { title, changes } = props;
|
||||
|
||||
if (changes.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const uniqueChanges = [...new Set(changes)];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.title}>{title}</div>
|
||||
<ul>
|
||||
{uniqueChanges.map((change, index) => {
|
||||
const checkChange = change.replace(
|
||||
/#\d{3,5}\b/g,
|
||||
(match) =>
|
||||
`[${match}](https://github.com/Prowlarr/Prowlarr/issues/${match.substring(
|
||||
1
|
||||
)})`
|
||||
);
|
||||
|
||||
return (
|
||||
<li key={index}>
|
||||
<InlineMarkdown data={checkChange} />
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default UpdateChanges;
|
||||
@@ -1,252 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import Icon from 'Components/Icon';
|
||||
import Label from 'Components/Label';
|
||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import formatDate from 'Utilities/Date/formatDate';
|
||||
import formatDateTime from 'Utilities/Date/formatDateTime';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import UpdateChanges from './UpdateChanges';
|
||||
import styles from './Updates.css';
|
||||
|
||||
class Updates extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
currentVersion,
|
||||
isFetching,
|
||||
isPopulated,
|
||||
updatesError,
|
||||
generalSettingsError,
|
||||
items,
|
||||
isInstallingUpdate,
|
||||
updateMechanism,
|
||||
isDocker,
|
||||
updateMechanismMessage,
|
||||
shortDateFormat,
|
||||
longDateFormat,
|
||||
timeFormat,
|
||||
onInstallLatestPress
|
||||
} = this.props;
|
||||
|
||||
const hasError = !!(updatesError || generalSettingsError);
|
||||
const hasUpdates = isPopulated && !hasError && items.length > 0;
|
||||
const noUpdates = isPopulated && !hasError && !items.length;
|
||||
const hasUpdateToInstall = hasUpdates && _.some(items, { installable: true, latest: true });
|
||||
const noUpdateToInstall = hasUpdates && !hasUpdateToInstall;
|
||||
|
||||
const externalUpdaterPrefix = 'Unable to update Prowlarr directly,';
|
||||
const externalUpdaterMessages = {
|
||||
external: 'Prowlarr is configured to use an external update mechanism',
|
||||
apt: 'use apt to install the update',
|
||||
docker: 'update the docker container to receive the update'
|
||||
};
|
||||
|
||||
return (
|
||||
<PageContent title={translate('Updates')}>
|
||||
<PageContentBody>
|
||||
{
|
||||
!isPopulated && !hasError &&
|
||||
<LoadingIndicator />
|
||||
}
|
||||
|
||||
{
|
||||
noUpdates &&
|
||||
<Alert kind={kinds.INFO}>
|
||||
{translate('NoUpdatesAreAvailable')}
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
hasUpdateToInstall &&
|
||||
<div className={styles.messageContainer}>
|
||||
{
|
||||
(updateMechanism === 'builtIn' || updateMechanism === 'script') && !isDocker ?
|
||||
<SpinnerButton
|
||||
className={styles.updateAvailable}
|
||||
kind={kinds.PRIMARY}
|
||||
isSpinning={isInstallingUpdate}
|
||||
onPress={onInstallLatestPress}
|
||||
>
|
||||
Install Latest
|
||||
</SpinnerButton> :
|
||||
|
||||
<Fragment>
|
||||
<Icon
|
||||
name={icons.WARNING}
|
||||
kind={kinds.WARNING}
|
||||
size={30}
|
||||
/>
|
||||
|
||||
<div className={styles.message}>
|
||||
{externalUpdaterPrefix} <InlineMarkdown data={updateMechanismMessage || externalUpdaterMessages[updateMechanism] || externalUpdaterMessages.external} />
|
||||
</div>
|
||||
</Fragment>
|
||||
}
|
||||
|
||||
{
|
||||
isFetching &&
|
||||
<LoadingIndicator
|
||||
className={styles.loading}
|
||||
size={20}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
noUpdateToInstall &&
|
||||
<div className={styles.messageContainer}>
|
||||
<Icon
|
||||
className={styles.upToDateIcon}
|
||||
name={icons.CHECK_CIRCLE}
|
||||
size={30}
|
||||
/>
|
||||
|
||||
<div className={styles.message}>
|
||||
{translate('TheLatestVersionIsAlreadyInstalled')}
|
||||
</div>
|
||||
|
||||
{
|
||||
isFetching &&
|
||||
<LoadingIndicator
|
||||
className={styles.loading}
|
||||
size={20}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
hasUpdates &&
|
||||
<div>
|
||||
{
|
||||
items.map((update) => {
|
||||
const hasChanges = !!update.changes;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={update.version}
|
||||
className={styles.update}
|
||||
>
|
||||
<div className={styles.info}>
|
||||
<div className={styles.version}>{update.version}</div>
|
||||
<div className={styles.space}>—</div>
|
||||
<div
|
||||
className={styles.date}
|
||||
title={formatDateTime(update.releaseDate, longDateFormat, timeFormat)}
|
||||
>
|
||||
{formatDate(update.releaseDate, shortDateFormat)}
|
||||
</div>
|
||||
|
||||
{
|
||||
update.branch === 'master' ?
|
||||
null:
|
||||
<Label
|
||||
className={styles.label}
|
||||
>
|
||||
{update.branch}
|
||||
</Label>
|
||||
}
|
||||
|
||||
{
|
||||
update.version === currentVersion ?
|
||||
<Label
|
||||
className={styles.label}
|
||||
kind={kinds.SUCCESS}
|
||||
title={formatDateTime(update.installedOn, longDateFormat, timeFormat)}
|
||||
>
|
||||
Currently Installed
|
||||
</Label> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
update.version !== currentVersion && update.installedOn ?
|
||||
<Label
|
||||
className={styles.label}
|
||||
kind={kinds.INVERSE}
|
||||
title={formatDateTime(update.installedOn, longDateFormat, timeFormat)}
|
||||
>
|
||||
Previously Installed
|
||||
</Label> :
|
||||
null
|
||||
}
|
||||
</div>
|
||||
|
||||
{
|
||||
!hasChanges &&
|
||||
<div>
|
||||
{translate('MaintenanceRelease')}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
hasChanges &&
|
||||
<div className={styles.changes}>
|
||||
<UpdateChanges
|
||||
title={translate('New')}
|
||||
changes={update.changes.new}
|
||||
/>
|
||||
|
||||
<UpdateChanges
|
||||
title={translate('Fixed')}
|
||||
changes={update.changes.fixed}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
!!updatesError &&
|
||||
<div>
|
||||
Failed to fetch updates
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
!!generalSettingsError &&
|
||||
<div>
|
||||
Failed to update settings
|
||||
</div>
|
||||
}
|
||||
</PageContentBody>
|
||||
</PageContent>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Updates.propTypes = {
|
||||
currentVersion: PropTypes.string.isRequired,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
updatesError: PropTypes.object,
|
||||
generalSettingsError: PropTypes.object,
|
||||
items: PropTypes.array.isRequired,
|
||||
isInstallingUpdate: PropTypes.bool.isRequired,
|
||||
isDocker: PropTypes.bool.isRequired,
|
||||
updateMechanism: PropTypes.string,
|
||||
updateMechanismMessage: PropTypes.string,
|
||||
shortDateFormat: PropTypes.string.isRequired,
|
||||
longDateFormat: PropTypes.string.isRequired,
|
||||
timeFormat: PropTypes.string.isRequired,
|
||||
onInstallLatestPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default Updates;
|
||||
303
frontend/src/System/Updates/Updates.tsx
Normal file
303
frontend/src/System/Updates/Updates.tsx
Normal file
@@ -0,0 +1,303 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import AppState from 'App/State/AppState';
|
||||
import * as commandNames from 'Commands/commandNames';
|
||||
import Alert from 'Components/Alert';
|
||||
import Icon from 'Components/Icon';
|
||||
import Label from 'Components/Label';
|
||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import { fetchGeneralSettings } from 'Store/Actions/settingsActions';
|
||||
import { fetchUpdates } from 'Store/Actions/systemActions';
|
||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||
import createSystemStatusSelector from 'Store/Selectors/createSystemStatusSelector';
|
||||
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
||||
import { UpdateMechanism } from 'typings/Settings/General';
|
||||
import formatDate from 'Utilities/Date/formatDate';
|
||||
import formatDateTime from 'Utilities/Date/formatDateTime';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import UpdateChanges from './UpdateChanges';
|
||||
import styles from './Updates.css';
|
||||
|
||||
const VERSION_REGEX = /\d+\.\d+\.\d+\.\d+/i;
|
||||
|
||||
function createUpdatesSelector() {
|
||||
return createSelector(
|
||||
(state: AppState) => state.system.updates,
|
||||
(state: AppState) => state.settings.general,
|
||||
(updates, generalSettings) => {
|
||||
const { error: updatesError, items } = updates;
|
||||
|
||||
const isFetching = updates.isFetching || generalSettings.isFetching;
|
||||
const isPopulated = updates.isPopulated && generalSettings.isPopulated;
|
||||
|
||||
return {
|
||||
isFetching,
|
||||
isPopulated,
|
||||
updatesError,
|
||||
generalSettingsError: generalSettings.error,
|
||||
items,
|
||||
updateMechanism: generalSettings.item.updateMechanism,
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function Updates() {
|
||||
const currentVersion = useSelector((state: AppState) => state.app.version);
|
||||
const { packageUpdateMechanismMessage } = useSelector(
|
||||
createSystemStatusSelector()
|
||||
);
|
||||
const { shortDateFormat, longDateFormat, timeFormat } = useSelector(
|
||||
createUISettingsSelector()
|
||||
);
|
||||
const isInstallingUpdate = useSelector(
|
||||
createCommandExecutingSelector(commandNames.APPLICATION_UPDATE)
|
||||
);
|
||||
|
||||
const {
|
||||
isFetching,
|
||||
isPopulated,
|
||||
updatesError,
|
||||
generalSettingsError,
|
||||
items,
|
||||
updateMechanism,
|
||||
} = useSelector(createUpdatesSelector());
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [isMajorUpdateModalOpen, setIsMajorUpdateModalOpen] = useState(false);
|
||||
const hasError = !!(updatesError || generalSettingsError);
|
||||
const hasUpdates = isPopulated && !hasError && items.length > 0;
|
||||
const noUpdates = isPopulated && !hasError && !items.length;
|
||||
|
||||
const externalUpdaterPrefix = translate('UpdateAppDirectlyLoadError');
|
||||
const externalUpdaterMessages: Partial<Record<UpdateMechanism, string>> = {
|
||||
external: translate('ExternalUpdater'),
|
||||
apt: translate('AptUpdater'),
|
||||
docker: translate('DockerUpdater'),
|
||||
};
|
||||
|
||||
const { isMajorUpdate, hasUpdateToInstall } = useMemo(() => {
|
||||
const majorVersion = parseInt(
|
||||
currentVersion.match(VERSION_REGEX)?.[0] ?? '0'
|
||||
);
|
||||
|
||||
const latestVersion = items[0]?.version;
|
||||
const latestMajorVersion = parseInt(
|
||||
latestVersion?.match(VERSION_REGEX)?.[0] ?? '0'
|
||||
);
|
||||
|
||||
return {
|
||||
isMajorUpdate: latestMajorVersion > majorVersion,
|
||||
hasUpdateToInstall: items.some(
|
||||
(update) => update.installable && update.latest
|
||||
),
|
||||
};
|
||||
}, [currentVersion, items]);
|
||||
|
||||
const noUpdateToInstall = hasUpdates && !hasUpdateToInstall;
|
||||
|
||||
const handleInstallLatestPress = useCallback(() => {
|
||||
if (isMajorUpdate) {
|
||||
setIsMajorUpdateModalOpen(true);
|
||||
} else {
|
||||
dispatch(executeCommand({ name: commandNames.APPLICATION_UPDATE }));
|
||||
}
|
||||
}, [isMajorUpdate, setIsMajorUpdateModalOpen, dispatch]);
|
||||
|
||||
const handleInstallLatestMajorVersionPress = useCallback(() => {
|
||||
setIsMajorUpdateModalOpen(false);
|
||||
|
||||
dispatch(
|
||||
executeCommand({
|
||||
name: commandNames.APPLICATION_UPDATE,
|
||||
installMajorUpdate: true,
|
||||
})
|
||||
);
|
||||
}, [setIsMajorUpdateModalOpen, dispatch]);
|
||||
|
||||
const handleCancelMajorVersionPress = useCallback(() => {
|
||||
setIsMajorUpdateModalOpen(false);
|
||||
}, [setIsMajorUpdateModalOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchUpdates());
|
||||
dispatch(fetchGeneralSettings());
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<PageContent title={translate('Updates')}>
|
||||
<PageContentBody>
|
||||
{isPopulated || hasError ? null : <LoadingIndicator />}
|
||||
|
||||
{noUpdates ? (
|
||||
<Alert kind={kinds.INFO}>{translate('NoUpdatesAreAvailable')}</Alert>
|
||||
) : null}
|
||||
|
||||
{hasUpdateToInstall ? (
|
||||
<div className={styles.messageContainer}>
|
||||
{updateMechanism === 'builtIn' || updateMechanism === 'script' ? (
|
||||
<SpinnerButton
|
||||
kind={kinds.PRIMARY}
|
||||
isSpinning={isInstallingUpdate}
|
||||
onPress={handleInstallLatestPress}
|
||||
>
|
||||
{translate('InstallLatest')}
|
||||
</SpinnerButton>
|
||||
) : (
|
||||
<>
|
||||
<Icon name={icons.WARNING} kind={kinds.WARNING} size={30} />
|
||||
|
||||
<div className={styles.message}>
|
||||
{externalUpdaterPrefix}{' '}
|
||||
<InlineMarkdown
|
||||
data={
|
||||
packageUpdateMechanismMessage ||
|
||||
externalUpdaterMessages[updateMechanism] ||
|
||||
externalUpdaterMessages.external
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isFetching ? (
|
||||
<LoadingIndicator className={styles.loading} size={20} />
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{noUpdateToInstall && (
|
||||
<div className={styles.messageContainer}>
|
||||
<Icon
|
||||
className={styles.upToDateIcon}
|
||||
name={icons.CHECK_CIRCLE}
|
||||
size={30}
|
||||
/>
|
||||
<div className={styles.message}>{translate('OnLatestVersion')}</div>
|
||||
|
||||
{isFetching && (
|
||||
<LoadingIndicator className={styles.loading} size={20} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{hasUpdates && (
|
||||
<div>
|
||||
{items.map((update) => {
|
||||
return (
|
||||
<div key={update.version} className={styles.update}>
|
||||
<div className={styles.info}>
|
||||
<div className={styles.version}>{update.version}</div>
|
||||
<div className={styles.space}>—</div>
|
||||
<div
|
||||
className={styles.date}
|
||||
title={formatDateTime(
|
||||
update.releaseDate,
|
||||
longDateFormat,
|
||||
timeFormat
|
||||
)}
|
||||
>
|
||||
{formatDate(update.releaseDate, shortDateFormat)}
|
||||
</div>
|
||||
|
||||
{update.branch === 'master' ? null : (
|
||||
<Label className={styles.label}>{update.branch}</Label>
|
||||
)}
|
||||
|
||||
{update.version === currentVersion ? (
|
||||
<Label
|
||||
className={styles.label}
|
||||
kind={kinds.SUCCESS}
|
||||
title={formatDateTime(
|
||||
update.installedOn,
|
||||
longDateFormat,
|
||||
timeFormat
|
||||
)}
|
||||
>
|
||||
{translate('CurrentlyInstalled')}
|
||||
</Label>
|
||||
) : null}
|
||||
|
||||
{update.version !== currentVersion && update.installedOn ? (
|
||||
<Label
|
||||
className={styles.label}
|
||||
kind={kinds.INVERSE}
|
||||
title={formatDateTime(
|
||||
update.installedOn,
|
||||
longDateFormat,
|
||||
timeFormat
|
||||
)}
|
||||
>
|
||||
{translate('PreviouslyInstalled')}
|
||||
</Label>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{update.changes ? (
|
||||
<div>
|
||||
<UpdateChanges
|
||||
title={translate('New')}
|
||||
changes={update.changes.new}
|
||||
/>
|
||||
|
||||
<UpdateChanges
|
||||
title={translate('Fixed')}
|
||||
changes={update.changes.fixed}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div>{translate('MaintenanceRelease')}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{updatesError ? (
|
||||
<Alert kind={kinds.WARNING}>
|
||||
{translate('FailedToFetchUpdates')}
|
||||
</Alert>
|
||||
) : null}
|
||||
|
||||
{generalSettingsError ? (
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('FailedToFetchSettings')}
|
||||
</Alert>
|
||||
) : null}
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={isMajorUpdateModalOpen}
|
||||
kind={kinds.WARNING}
|
||||
title={translate('InstallMajorVersionUpdate')}
|
||||
message={
|
||||
<div>
|
||||
<div>{translate('InstallMajorVersionUpdateMessage')}</div>
|
||||
<div>
|
||||
<InlineMarkdown
|
||||
data={translate('InstallMajorVersionUpdateMessageLink', {
|
||||
domain: 'prowlarr.com',
|
||||
url: 'https://prowlarr.com/#downloads',
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
confirmLabel={translate('Install')}
|
||||
onConfirm={handleInstallLatestMajorVersionPress}
|
||||
onCancel={handleCancelMajorVersionPress}
|
||||
/>
|
||||
</PageContentBody>
|
||||
</PageContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default Updates;
|
||||
@@ -1,101 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import * as commandNames from 'Commands/commandNames';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import { fetchGeneralSettings } from 'Store/Actions/settingsActions';
|
||||
import { fetchUpdates } from 'Store/Actions/systemActions';
|
||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||
import createSystemStatusSelector from 'Store/Selectors/createSystemStatusSelector';
|
||||
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
||||
import Updates from './Updates';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.app.version,
|
||||
createSystemStatusSelector(),
|
||||
(state) => state.system.updates,
|
||||
(state) => state.settings.general,
|
||||
createUISettingsSelector(),
|
||||
createSystemStatusSelector(),
|
||||
createCommandExecutingSelector(commandNames.APPLICATION_UPDATE),
|
||||
(
|
||||
currentVersion,
|
||||
status,
|
||||
updates,
|
||||
generalSettings,
|
||||
uiSettings,
|
||||
systemStatus,
|
||||
isInstallingUpdate
|
||||
) => {
|
||||
const {
|
||||
error: updatesError,
|
||||
items
|
||||
} = updates;
|
||||
|
||||
const isFetching = updates.isFetching || generalSettings.isFetching;
|
||||
const isPopulated = updates.isPopulated && generalSettings.isPopulated;
|
||||
|
||||
return {
|
||||
currentVersion,
|
||||
isFetching,
|
||||
isPopulated,
|
||||
updatesError,
|
||||
generalSettingsError: generalSettings.error,
|
||||
items,
|
||||
isInstallingUpdate,
|
||||
isDocker: systemStatus.isDocker,
|
||||
updateMechanism: generalSettings.item.updateMechanism,
|
||||
updateMechanismMessage: status.packageUpdateMechanismMessage,
|
||||
shortDateFormat: uiSettings.shortDateFormat,
|
||||
longDateFormat: uiSettings.longDateFormat,
|
||||
timeFormat: uiSettings.timeFormat
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
dispatchFetchUpdates: fetchUpdates,
|
||||
dispatchFetchGeneralSettings: fetchGeneralSettings,
|
||||
dispatchExecuteCommand: executeCommand
|
||||
};
|
||||
|
||||
class UpdatesConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatchFetchUpdates();
|
||||
this.props.dispatchFetchGeneralSettings();
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onInstallLatestPress = () => {
|
||||
this.props.dispatchExecuteCommand({ name: commandNames.APPLICATION_UPDATE });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Updates
|
||||
onInstallLatestPress={this.onInstallLatestPress}
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
UpdatesConnector.propTypes = {
|
||||
dispatchFetchUpdates: PropTypes.func.isRequired,
|
||||
dispatchFetchGeneralSettings: PropTypes.func.isRequired,
|
||||
dispatchExecuteCommand: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(UpdatesConnector);
|
||||
45
frontend/src/typings/Settings/General.ts
Normal file
45
frontend/src/typings/Settings/General.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
export type UpdateMechanism =
|
||||
| 'builtIn'
|
||||
| 'script'
|
||||
| 'external'
|
||||
| 'apt'
|
||||
| 'docker';
|
||||
|
||||
export default interface General {
|
||||
bindAddress: string;
|
||||
port: number;
|
||||
sslPort: number;
|
||||
enableSsl: boolean;
|
||||
launchBrowser: boolean;
|
||||
authenticationMethod: string;
|
||||
authenticationRequired: string;
|
||||
analyticsEnabled: boolean;
|
||||
username: string;
|
||||
password: string;
|
||||
passwordConfirmation: string;
|
||||
logLevel: string;
|
||||
consoleLogLevel: string;
|
||||
branch: string;
|
||||
apiKey: string;
|
||||
sslCertPath: string;
|
||||
sslCertPassword: string;
|
||||
urlBase: string;
|
||||
instanceName: string;
|
||||
applicationUrl: string;
|
||||
updateAutomatically: boolean;
|
||||
updateMechanism: UpdateMechanism;
|
||||
updateScriptPath: string;
|
||||
proxyEnabled: boolean;
|
||||
proxyType: string;
|
||||
proxyHostname: string;
|
||||
proxyPort: number;
|
||||
proxyUsername: string;
|
||||
proxyPassword: string;
|
||||
proxyBypassFilter: string;
|
||||
proxyBypassLocalAddresses: boolean;
|
||||
certificateValidation: string;
|
||||
backupFolder: string;
|
||||
backupInterval: number;
|
||||
backupRetention: number;
|
||||
id: number;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export interface UiSettings {
|
||||
export default interface UiSettings {
|
||||
theme: 'auto' | 'dark' | 'light';
|
||||
showRelativeDates: boolean;
|
||||
shortDateFormat: string;
|
||||
@@ -22,6 +22,7 @@ interface SystemStatus {
|
||||
osVersion: string;
|
||||
packageAuthor: string;
|
||||
packageUpdateMechanism: string;
|
||||
packageUpdateMechanismMessage: string;
|
||||
packageVersion: string;
|
||||
runtimeName: string;
|
||||
runtimeVersion: string;
|
||||
|
||||
@@ -133,11 +133,16 @@ namespace NzbDrone.Common.Test
|
||||
|
||||
[TestCase(@"C:\test\", @"C:\Test\mydir")]
|
||||
[TestCase(@"C:\test", @"C:\Test\mydir\")]
|
||||
public void path_should_be_parent_on_windows_only(string parentPath, string childPath)
|
||||
public void windows_path_should_be_parent(string parentPath, string childPath)
|
||||
{
|
||||
var expectedResult = OsInfo.IsWindows;
|
||||
parentPath.IsParentPath(childPath).Should().Be(true);
|
||||
}
|
||||
|
||||
parentPath.IsParentPath(childPath).Should().Be(expectedResult);
|
||||
[TestCase("/test", "/test/mydir/")]
|
||||
[TestCase("/test/", "/test/mydir")]
|
||||
public void posix_path_should_be_parent(string parentPath, string childPath)
|
||||
{
|
||||
parentPath.IsParentPath(childPath).Should().Be(true);
|
||||
}
|
||||
|
||||
[TestCase(@"C:\Test\mydir", @"C:\Test")]
|
||||
@@ -145,20 +150,57 @@ namespace NzbDrone.Common.Test
|
||||
[TestCase(@"C:\", null)]
|
||||
[TestCase(@"\\server\share", null)]
|
||||
[TestCase(@"\\server\share\test", @"\\server\share")]
|
||||
public void path_should_return_parent_windows(string path, string parentPath)
|
||||
public void windows_path_should_return_parent(string path, string parentPath)
|
||||
{
|
||||
WindowsOnly();
|
||||
path.GetParentPath().Should().Be(parentPath);
|
||||
}
|
||||
|
||||
[TestCase(@"/", null)]
|
||||
[TestCase(@"/test", "/")]
|
||||
public void path_should_return_parent_mono(string path, string parentPath)
|
||||
[TestCase(@"/test/tv", "/test")]
|
||||
public void unix_path_should_return_parent(string path, string parentPath)
|
||||
{
|
||||
PosixOnly();
|
||||
path.GetParentPath().Should().Be(parentPath);
|
||||
}
|
||||
|
||||
[TestCase(@"C:\Test\mydir", "Test")]
|
||||
[TestCase(@"C:\Test\", @"C:\")]
|
||||
[TestCase(@"C:\Test", @"C:\")]
|
||||
[TestCase(@"C:\", null)]
|
||||
[TestCase(@"\\server\share", null)]
|
||||
[TestCase(@"\\server\share\test", @"\\server\share")]
|
||||
public void path_should_return_parent_name_windows(string path, string parentPath)
|
||||
{
|
||||
path.GetParentName().Should().Be(parentPath);
|
||||
}
|
||||
|
||||
[TestCase(@"/", null)]
|
||||
[TestCase(@"/test", "/")]
|
||||
[TestCase(@"/test/tv", "test")]
|
||||
public void path_should_return_parent_name_mono(string path, string parentPath)
|
||||
{
|
||||
path.GetParentName().Should().Be(parentPath);
|
||||
}
|
||||
|
||||
[TestCase(@"C:\Test\mydir", "mydir")]
|
||||
[TestCase(@"C:\Test\", "Test")]
|
||||
[TestCase(@"C:\Test", "Test")]
|
||||
[TestCase(@"C:\", "C:\\")]
|
||||
[TestCase(@"\\server\share", @"\\server\share")]
|
||||
[TestCase(@"\\server\share\test", "test")]
|
||||
public void path_should_return_directory_name_windows(string path, string parentPath)
|
||||
{
|
||||
path.GetDirectoryName().Should().Be(parentPath);
|
||||
}
|
||||
|
||||
[TestCase(@"/", "/")]
|
||||
[TestCase(@"/test", "test")]
|
||||
[TestCase(@"/test/tv", "tv")]
|
||||
public void path_should_return_directory_name_mono(string path, string parentPath)
|
||||
{
|
||||
path.GetDirectoryName().Should().Be(parentPath);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void path_should_return_parent_for_oversized_path()
|
||||
{
|
||||
@@ -166,7 +208,7 @@ namespace NzbDrone.Common.Test
|
||||
|
||||
// This test will fail on Windows if long path support is not enabled: https://www.howtogeek.com/266621/how-to-make-windows-10-accept-file-paths-over-260-characters/
|
||||
// It will also fail if the app isn't configured to use long path (such as resharper): https://blogs.msdn.microsoft.com/jeremykuhne/2016/07/30/net-4-6-2-and-long-paths-on-windows-10/
|
||||
var path = @"C:\media\2e168617-f2ae-43fb-b88c-3663af1c8eea\downloads\sabnzbd\nzbdrone\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories".AsOsAgnostic();
|
||||
var path = @"C:\media\2e168617-f2ae-43fb-b88c-3663af1c8eea\downloads\sabnzbd\nzbdrone\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories".AsOsAgnostic();
|
||||
var parentPath = @"C:\media\2e168617-f2ae-43fb-b88c-3663af1c8eea\downloads\sabnzbd\nzbdrone\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing".AsOsAgnostic();
|
||||
|
||||
path.GetParentPath().Should().Be(parentPath);
|
||||
@@ -350,5 +392,46 @@ namespace NzbDrone.Common.Test
|
||||
PosixOnly();
|
||||
path.AsOsAgnostic().IsPathValid(PathValidationType.CurrentOs).Should().BeFalse();
|
||||
}
|
||||
|
||||
[TestCase(@"C:\", @"C:\")]
|
||||
[TestCase(@"C:\\", @"C:\")]
|
||||
[TestCase(@"C:\Test", @"C:\Test")]
|
||||
[TestCase(@"C:\Test\", @"C:\Test")]
|
||||
[TestCase(@"\\server\share", @"\\server\share")]
|
||||
[TestCase(@"\\server\share\", @"\\server\share")]
|
||||
public void windows_path_should_return_clean_path(string path, string cleanPath)
|
||||
{
|
||||
path.GetCleanPath().Should().Be(cleanPath);
|
||||
}
|
||||
|
||||
[TestCase("/", "/")]
|
||||
[TestCase("//", "/")]
|
||||
[TestCase("/test", "/test")]
|
||||
[TestCase("/test/", "/test")]
|
||||
[TestCase("/test//", "/test")]
|
||||
public void unix_path_should_return_clean_path(string path, string cleanPath)
|
||||
{
|
||||
path.GetCleanPath().Should().Be(cleanPath);
|
||||
}
|
||||
|
||||
[TestCase(@"C:\Test\", @"C:\Test\Series Title", "Series Title")]
|
||||
[TestCase(@"C:\Test\", @"C:\Test\Collection\Series Title", @"Collection\Series Title")]
|
||||
[TestCase(@"C:\Test\mydir\", @"C:\Test\mydir\Collection\Series Title", @"Collection\Series Title")]
|
||||
[TestCase(@"\\server\share", @"\\server\share\Series Title", "Series Title")]
|
||||
[TestCase(@"\\server\share\mydir\", @"\\server\share\mydir\/Collection\Series Title", @"Collection\Series Title")]
|
||||
public void windows_path_should_return_relative_path(string parentPath, string childPath, string relativePath)
|
||||
{
|
||||
parentPath.GetRelativePath(childPath).Should().Be(relativePath);
|
||||
}
|
||||
|
||||
[TestCase(@"/test", "/test/Series Title", "Series Title")]
|
||||
[TestCase(@"/test/", "/test/Collection/Series Title", "Collection/Series Title")]
|
||||
[TestCase(@"/test/mydir", "/test/mydir/Series Title", "Series Title")]
|
||||
[TestCase(@"/test/mydir/", "/test/mydir/Collection/Series Title", "Collection/Series Title")]
|
||||
[TestCase(@"/test/mydir/", @"/test/mydir/\Collection/Series Title", "Collection/Series Title")]
|
||||
public void unix_path_should_return_relative_path(string parentPath, string childPath, string relativePath)
|
||||
{
|
||||
parentPath.GetRelativePath(childPath).Should().Be(relativePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace NzbDrone.Common.Disk
|
||||
@@ -9,6 +10,8 @@ namespace NzbDrone.Common.Disk
|
||||
private readonly string _path;
|
||||
private readonly OsPathKind _kind;
|
||||
|
||||
private static readonly Regex UncPathRegex = new Regex(@"(?<unc>^\\\\(?:\?\\UNC\\)?[^\\]+\\[^\\]+)(?:\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public OsPath(string path)
|
||||
{
|
||||
if (path == null)
|
||||
@@ -96,6 +99,29 @@ namespace NzbDrone.Common.Disk
|
||||
return path;
|
||||
}
|
||||
|
||||
private static string TrimTrailingSlash(string path, OsPathKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case OsPathKind.Windows when !path.EndsWith(":\\"):
|
||||
while (!path.EndsWith(":\\") && path.EndsWith('\\'))
|
||||
{
|
||||
path = path[..^1];
|
||||
}
|
||||
|
||||
return path;
|
||||
case OsPathKind.Unix when path != "/":
|
||||
while (path != "/" && path.EndsWith('/'))
|
||||
{
|
||||
path = path[..^1];
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public OsPathKind Kind => _kind;
|
||||
|
||||
public bool IsWindowsPath => _kind == OsPathKind.Windows;
|
||||
@@ -130,7 +156,19 @@ namespace NzbDrone.Common.Disk
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
return new OsPath(null);
|
||||
return Null;
|
||||
}
|
||||
|
||||
var rootLength = GetRootLength();
|
||||
|
||||
if (rootLength == _path.Length)
|
||||
{
|
||||
return Null;
|
||||
}
|
||||
|
||||
if (rootLength > index + 1)
|
||||
{
|
||||
return new OsPath(_path.Substring(0, rootLength));
|
||||
}
|
||||
|
||||
return new OsPath(_path.Substring(0, index), _kind).AsDirectory();
|
||||
@@ -139,6 +177,8 @@ namespace NzbDrone.Common.Disk
|
||||
|
||||
public string FullPath => _path;
|
||||
|
||||
public string PathWithoutTrailingSlash => TrimTrailingSlash(_path, _kind);
|
||||
|
||||
public string FileName
|
||||
{
|
||||
get
|
||||
@@ -161,6 +201,29 @@ namespace NzbDrone.Common.Disk
|
||||
}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
// Meant to behave similar to DirectoryInfo.Name
|
||||
get
|
||||
{
|
||||
var index = GetFileNameIndex();
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
return PathWithoutTrailingSlash;
|
||||
}
|
||||
|
||||
var rootLength = GetRootLength();
|
||||
|
||||
if (rootLength > index + 1)
|
||||
{
|
||||
return _path.Substring(0, rootLength);
|
||||
}
|
||||
|
||||
return TrimTrailingSlash(_path.Substring(index).TrimStart('/', '\\'), _kind);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValid => _path.IsPathValid(PathValidationType.CurrentOs);
|
||||
|
||||
private int GetFileNameIndex()
|
||||
@@ -190,11 +253,50 @@ namespace NzbDrone.Common.Disk
|
||||
return index;
|
||||
}
|
||||
|
||||
private int GetRootLength()
|
||||
{
|
||||
if (!IsRooted)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_kind == OsPathKind.Unix)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_kind == OsPathKind.Windows)
|
||||
{
|
||||
if (HasWindowsDriveLetter(_path))
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
var uncMatch = UncPathRegex.Match(_path);
|
||||
|
||||
// \\?\UNC\server\share\ or \\server\share
|
||||
if (uncMatch.Success)
|
||||
{
|
||||
return uncMatch.Groups["unc"].Length;
|
||||
}
|
||||
|
||||
// \\?\C:\
|
||||
if (_path.StartsWith(@"\\?\"))
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private string[] GetFragments()
|
||||
{
|
||||
return _path.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public static OsPath Null => new (null);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _path;
|
||||
@@ -267,6 +369,11 @@ namespace NzbDrone.Common.Disk
|
||||
}
|
||||
|
||||
public bool Equals(OsPath other)
|
||||
{
|
||||
return Equals(other, false);
|
||||
}
|
||||
|
||||
public bool Equals(OsPath other, bool ignoreTrailingSlash)
|
||||
{
|
||||
if (ReferenceEquals(other, null))
|
||||
{
|
||||
@@ -278,8 +385,8 @@ namespace NzbDrone.Common.Disk
|
||||
return true;
|
||||
}
|
||||
|
||||
var left = _path;
|
||||
var right = other._path;
|
||||
var left = ignoreTrailingSlash ? PathWithoutTrailingSlash : _path;
|
||||
var right = ignoreTrailingSlash ? other.PathWithoutTrailingSlash : other._path;
|
||||
|
||||
if (Kind == OsPathKind.Windows || other.Kind == OsPathKind.Windows)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
@@ -25,22 +24,25 @@ namespace NzbDrone.Common.EnvironmentInfo
|
||||
|
||||
static OsInfo()
|
||||
{
|
||||
var platform = Environment.OSVersion.Platform;
|
||||
|
||||
switch (platform)
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
{
|
||||
Os = Os.Windows;
|
||||
break;
|
||||
}
|
||||
|
||||
case PlatformID.MacOSX:
|
||||
case PlatformID.Unix:
|
||||
{
|
||||
Os = GetPosixFlavour();
|
||||
break;
|
||||
}
|
||||
Os = Os.Windows;
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
Os = Os.Osx;
|
||||
}
|
||||
else if (OperatingSystem.IsFreeBSD())
|
||||
{
|
||||
Os = Os.Bsd;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if ISMUSL
|
||||
Os = Os.LinuxMusl;
|
||||
#else
|
||||
Os = Os.Linux;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,59 +86,6 @@ namespace NzbDrone.Common.EnvironmentInfo
|
||||
IsDocker = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static Os GetPosixFlavour()
|
||||
{
|
||||
var output = RunAndCapture("uname", "-s");
|
||||
|
||||
if (output.StartsWith("Darwin"))
|
||||
{
|
||||
return Os.Osx;
|
||||
}
|
||||
else if (output.Contains("BSD"))
|
||||
{
|
||||
return Os.Bsd;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if ISMUSL
|
||||
return Os.LinuxMusl;
|
||||
#else
|
||||
return Os.Linux;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private static string RunAndCapture(string filename, string args)
|
||||
{
|
||||
var processStartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = filename,
|
||||
Arguments = args,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardOutput = true
|
||||
};
|
||||
|
||||
var output = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
using (var p = Process.Start(processStartInfo))
|
||||
{
|
||||
// To avoid deadlocks, always read the output stream first and then wait.
|
||||
output = p.StandardOutput.ReadToEnd();
|
||||
|
||||
p.WaitForExit(1000);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
output = string.Empty;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IOsInfo
|
||||
|
||||
@@ -25,8 +25,6 @@ namespace NzbDrone.Common.Extensions
|
||||
private static readonly string UPDATE_CLIENT_FOLDER_NAME = "Prowlarr.Update" + Path.DirectorySeparatorChar;
|
||||
private static readonly string UPDATE_LOG_FOLDER_NAME = "UpdateLogs" + Path.DirectorySeparatorChar;
|
||||
|
||||
private static readonly Regex PARENT_PATH_END_SLASH_REGEX = new Regex(@"(?<!:)\\$", RegexOptions.Compiled);
|
||||
|
||||
public static string CleanFilePath(this string path)
|
||||
{
|
||||
if (path.IsNotNullOrWhiteSpace())
|
||||
@@ -87,55 +85,50 @@ namespace NzbDrone.Common.Extensions
|
||||
throw new NotParentException("{0} is not a child of {1}", childPath, parentPath);
|
||||
}
|
||||
|
||||
return childPath.Substring(parentPath.Length).Trim(Path.DirectorySeparatorChar);
|
||||
return childPath.Substring(parentPath.Length).Trim('\\', '/');
|
||||
}
|
||||
|
||||
public static string GetParentPath(this string childPath)
|
||||
{
|
||||
var cleanPath = OsInfo.IsWindows
|
||||
? PARENT_PATH_END_SLASH_REGEX.Replace(childPath, "")
|
||||
: childPath.TrimEnd(Path.DirectorySeparatorChar);
|
||||
var path = new OsPath(childPath).Directory;
|
||||
|
||||
if (cleanPath.IsNullOrWhiteSpace())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return path == OsPath.Null ? null : path.PathWithoutTrailingSlash;
|
||||
}
|
||||
|
||||
return Directory.GetParent(cleanPath)?.FullName;
|
||||
public static string GetParentName(this string childPath)
|
||||
{
|
||||
var path = new OsPath(childPath).Directory;
|
||||
|
||||
return path == OsPath.Null ? null : path.Name;
|
||||
}
|
||||
|
||||
public static string GetDirectoryName(this string childPath)
|
||||
{
|
||||
var path = new OsPath(childPath);
|
||||
|
||||
return path == OsPath.Null ? null : path.Name;
|
||||
}
|
||||
|
||||
public static string GetCleanPath(this string path)
|
||||
{
|
||||
var cleanPath = OsInfo.IsWindows
|
||||
? PARENT_PATH_END_SLASH_REGEX.Replace(path, "")
|
||||
: path.TrimEnd(Path.DirectorySeparatorChar);
|
||||
var osPath = new OsPath(path);
|
||||
|
||||
return cleanPath;
|
||||
return osPath == OsPath.Null ? null : osPath.PathWithoutTrailingSlash;
|
||||
}
|
||||
|
||||
public static bool IsParentPath(this string parentPath, string childPath)
|
||||
{
|
||||
if (parentPath != "/" && !parentPath.EndsWith(":\\"))
|
||||
{
|
||||
parentPath = parentPath.TrimEnd(Path.DirectorySeparatorChar);
|
||||
}
|
||||
var parent = new OsPath(parentPath);
|
||||
var child = new OsPath(childPath);
|
||||
|
||||
if (childPath != "/" && !parentPath.EndsWith(":\\"))
|
||||
while (child.Directory != OsPath.Null)
|
||||
{
|
||||
childPath = childPath.TrimEnd(Path.DirectorySeparatorChar);
|
||||
}
|
||||
|
||||
var parent = new DirectoryInfo(parentPath);
|
||||
var child = new DirectoryInfo(childPath);
|
||||
|
||||
while (child.Parent != null)
|
||||
{
|
||||
if (child.Parent.FullName.Equals(parent.FullName, DiskProviderBase.PathStringComparison))
|
||||
if (child.Directory.Equals(parent, true))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
child = child.Parent;
|
||||
child = child.Directory;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -150,14 +143,14 @@ namespace NzbDrone.Common.Extensions
|
||||
return false;
|
||||
}
|
||||
|
||||
if (path.Trim() != path)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only check for leading or trailing spaces for path when running on Windows.
|
||||
if (OsInfo.IsWindows)
|
||||
{
|
||||
if (path.Trim() != path)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var directoryInfo = new DirectoryInfo(path);
|
||||
|
||||
while (directoryInfo != null)
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace NzbDrone.Common.Http
|
||||
|
||||
if (response.HasHttpRedirect && !RuntimeInfo.IsProduction)
|
||||
{
|
||||
_logger.Error("Server requested a redirect to [{0}] while in developer mode. Update the request URL to avoid this redirect.", response.Headers["Location"]);
|
||||
_logger.Error("Server requested a redirect to [{0}] while in developer mode. Update the request URL to avoid this redirect.", response.RedirectUrl);
|
||||
}
|
||||
|
||||
if (!request.SuppressHttpError && response.HasHttpError && (request.SuppressHttpErrorStatusCodes == null || !request.SuppressHttpErrorStatusCodes.Contains(response.StatusCode)))
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
|
||||
torrentInfo.InfoUrl.Should().Be("https://filelist.io/details.php?id=665873");
|
||||
torrentInfo.CommentUrl.Should().BeNullOrEmpty();
|
||||
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
|
||||
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2020-01-25 19:20:19"));
|
||||
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2020-01-25 20:20:19"));
|
||||
torrentInfo.Size.Should().Be(8300512414);
|
||||
torrentInfo.InfoHash.Should().Be(null);
|
||||
torrentInfo.MagnetUrl.Should().Be(null);
|
||||
|
||||
@@ -35,18 +35,18 @@ namespace NzbDrone.Core.Test.UpdateTests
|
||||
{
|
||||
_updatePackage = new UpdatePackage
|
||||
{
|
||||
FileName = "NzbDrone.develop.2.0.0.0.tar.gz",
|
||||
FileName = "NzbDrone.develop.1.0.0.0.tar.gz",
|
||||
Url = "http://download.sonarr.tv/v2/develop/mono/NzbDrone.develop.tar.gz",
|
||||
Version = new Version("2.0.0.0")
|
||||
Version = new Version("1.0.0.0")
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
_updatePackage = new UpdatePackage
|
||||
{
|
||||
FileName = "NzbDrone.develop.2.0.0.0.zip",
|
||||
FileName = "NzbDrone.develop.1.0.0.0.zip",
|
||||
Url = "http://download.sonarr.tv/v2/develop/windows/NzbDrone.develop.zip",
|
||||
Version = new Version("2.0.0.0")
|
||||
Version = new Version("1.0.0.0")
|
||||
};
|
||||
}
|
||||
|
||||
@@ -90,17 +90,6 @@ namespace NzbDrone.Core.Test.UpdateTests
|
||||
.Returns(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_if_inside_docker()
|
||||
{
|
||||
Mocker.GetMock<IOsInfo>().Setup(x => x.IsDocker).Returns(true);
|
||||
|
||||
Subject.Execute(new ApplicationUpdateCommand());
|
||||
|
||||
Mocker.GetMock<IProcessProvider>()
|
||||
.Verify(c => c.Start(It.IsAny<string>(), It.Is<string>(s => s.StartsWith("12")), null, null, null), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_delete_sandbox_before_update_if_folder_exists()
|
||||
{
|
||||
@@ -338,6 +327,28 @@ namespace NzbDrone.Core.Test.UpdateTests
|
||||
.Verify(v => v.SaveConfigDictionary(It.Is<Dictionary<string, object>>(d => d.ContainsKey("Branch") && (string)d["Branch"] == "fake")), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_with_built_in_updater_inside_docker_container()
|
||||
{
|
||||
Mocker.GetMock<IDeploymentInfoProvider>().Setup(x => x.PackageUpdateMechanism).Returns(UpdateMechanism.Docker);
|
||||
|
||||
Subject.Execute(new ApplicationUpdateCommand());
|
||||
|
||||
Mocker.GetMock<IProcessProvider>()
|
||||
.Verify(c => c.Start(It.IsAny<string>(), It.Is<string>(s => s.StartsWith("12")), null, null, null), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_with_built_in_updater_when_external_updater_is_configured()
|
||||
{
|
||||
Mocker.GetMock<IDeploymentInfoProvider>().Setup(x => x.IsExternalUpdateMechanism).Returns(true);
|
||||
|
||||
Subject.Execute(new ApplicationUpdateCommand());
|
||||
|
||||
Mocker.GetMock<IProcessProvider>()
|
||||
.Verify(c => c.Start(It.IsAny<string>(), It.Is<string>(s => s.StartsWith("12")), null, null, null), Times.Never());
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
|
||||
@@ -127,6 +127,8 @@ namespace NzbDrone.Core.Applications
|
||||
|
||||
private void SyncIndexers(List<IApplication> applications, List<IndexerDefinition> indexers, bool removeRemote = false, bool forceSync = false)
|
||||
{
|
||||
var sortedIndexers = indexers.OrderBy(i => i.Name, StringComparer.OrdinalIgnoreCase).ToList();
|
||||
|
||||
foreach (var app in applications)
|
||||
{
|
||||
var indexerMappings = _appIndexerMapService.GetMappingsForApp(app.Definition.Id);
|
||||
@@ -157,7 +159,7 @@ namespace NzbDrone.Core.Applications
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var indexer in indexers)
|
||||
foreach (var indexer in sortedIndexers)
|
||||
{
|
||||
var definition = indexer;
|
||||
|
||||
|
||||
@@ -25,8 +25,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
Dictionary<string, QBittorrentLabel> GetLabels(QBittorrentSettings settings);
|
||||
void SetTorrentSeedingConfiguration(string hash, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings);
|
||||
void MoveTorrentToTopInQueue(string hash, QBittorrentSettings settings);
|
||||
void PauseTorrent(string hash, QBittorrentSettings settings);
|
||||
void ResumeTorrent(string hash, QBittorrentSettings settings);
|
||||
void SetForceStart(string hash, bool enabled, QBittorrentSettings settings);
|
||||
}
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
{
|
||||
request.AddFormParameter("paused", false);
|
||||
}
|
||||
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Pause)
|
||||
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Stop)
|
||||
{
|
||||
request.AddFormParameter("paused", true);
|
||||
}
|
||||
@@ -176,7 +176,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
{
|
||||
request.AddFormParameter("paused", false);
|
||||
}
|
||||
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Pause)
|
||||
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Stop)
|
||||
{
|
||||
request.AddFormParameter("paused", true);
|
||||
}
|
||||
@@ -212,7 +212,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
catch (DownloadClientException ex)
|
||||
{
|
||||
// if setCategory fails due to method not being found, then try older setLabel command for qBittorrent < v.3.3.5
|
||||
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.NotFound)
|
||||
if (ex.InnerException is HttpException httpException && httpException.Response.StatusCode == HttpStatusCode.NotFound)
|
||||
{
|
||||
var setLabelRequest = BuildRequest(settings).Resource("/command/setLabel")
|
||||
.Post()
|
||||
@@ -254,7 +254,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
catch (DownloadClientException ex)
|
||||
{
|
||||
// qBittorrent rejects all Prio commands with 403: Forbidden if Options -> BitTorrent -> Torrent Queueing is not enabled
|
||||
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.Forbidden)
|
||||
if (ex.InnerException is HttpException httpException && httpException.Response.StatusCode == HttpStatusCode.Forbidden)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -263,22 +263,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
}
|
||||
}
|
||||
|
||||
public void PauseTorrent(string hash, QBittorrentSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings).Resource("/command/pause")
|
||||
.Post()
|
||||
.AddFormParameter("hash", hash);
|
||||
ProcessRequest(request, settings);
|
||||
}
|
||||
|
||||
public void ResumeTorrent(string hash, QBittorrentSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings).Resource("/command/resume")
|
||||
.Post()
|
||||
.AddFormParameter("hash", hash);
|
||||
ProcessRequest(request, settings);
|
||||
}
|
||||
|
||||
public void SetForceStart(string hash, bool enabled, QBittorrentSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings).Resource("/command/setForceStart")
|
||||
|
||||
@@ -246,14 +246,20 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
request.AddFormParameter("category", category);
|
||||
}
|
||||
|
||||
// Note: ForceStart is handled by separate api call
|
||||
if ((QBittorrentState)settings.InitialState == QBittorrentState.Start)
|
||||
// Avoid extraneous API version check if initial state is ForceStart
|
||||
if ((QBittorrentState)settings.InitialState is QBittorrentState.Start or QBittorrentState.Stop)
|
||||
{
|
||||
request.AddFormParameter("paused", false);
|
||||
}
|
||||
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Pause)
|
||||
{
|
||||
request.AddFormParameter("paused", true);
|
||||
var stoppedParameterName = GetApiVersion(settings) >= new Version(2, 11, 0) ? "stopped" : "paused";
|
||||
|
||||
// Note: ForceStart is handled by separate api call
|
||||
if ((QBittorrentState)settings.InitialState == QBittorrentState.Start)
|
||||
{
|
||||
request.AddFormParameter(stoppedParameterName, false);
|
||||
}
|
||||
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Stop)
|
||||
{
|
||||
request.AddFormParameter(stoppedParameterName, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.SequentialOrder)
|
||||
@@ -291,7 +297,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
catch (DownloadClientException ex)
|
||||
{
|
||||
// setShareLimits was added in api v2.0.1 so catch it case of the unlikely event that someone has api v2.0
|
||||
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.NotFound)
|
||||
if (ex.InnerException is HttpException httpException && httpException.Response.StatusCode == HttpStatusCode.NotFound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -313,7 +319,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
catch (DownloadClientException ex)
|
||||
{
|
||||
// qBittorrent rejects all Prio commands with 409: Conflict if Options -> BitTorrent -> Torrent Queueing is not enabled
|
||||
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.Conflict)
|
||||
if (ex.InnerException is HttpException httpException && httpException.Response.StatusCode == HttpStatusCode.Conflict)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -322,22 +328,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
}
|
||||
}
|
||||
|
||||
public void PauseTorrent(string hash, QBittorrentSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings).Resource("/api/v2/torrents/pause")
|
||||
.Post()
|
||||
.AddFormParameter("hashes", hash);
|
||||
ProcessRequest(request, settings);
|
||||
}
|
||||
|
||||
public void ResumeTorrent(string hash, QBittorrentSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings).Resource("/api/v2/torrents/resume")
|
||||
.Post()
|
||||
.AddFormParameter("hashes", hash);
|
||||
ProcessRequest(request, settings);
|
||||
}
|
||||
|
||||
public void SetForceStart(string hash, bool enabled, QBittorrentSettings settings)
|
||||
{
|
||||
var request = BuildRequest(settings).Resource("/api/v2/torrents/setForceStart")
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
using NzbDrone.Core.Annotations;
|
||||
|
||||
namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
{
|
||||
public enum QBittorrentState
|
||||
{
|
||||
[FieldOption(Label = "Started")]
|
||||
Start = 0,
|
||||
|
||||
[FieldOption(Label = "Force Started")]
|
||||
ForceStart = 1,
|
||||
Pause = 2
|
||||
|
||||
[FieldOption(Label = "Stopped")]
|
||||
Stop = 2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
||||
if (latestAvailable != null)
|
||||
{
|
||||
return new HealthCheck(GetType(),
|
||||
HealthCheckResult.Warning,
|
||||
BuildInfo.BuildDateTime.Before(DateTime.UtcNow.AddDays(-180)) ? HealthCheckResult.Error : HealthCheckResult.Warning,
|
||||
_localizationService.GetLocalizedString("UpdateAvailableHealthCheckMessage", new Dictionary<string, object>
|
||||
{
|
||||
{ "version", $"v{latestAvailable.Version}" }
|
||||
|
||||
@@ -326,8 +326,8 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
public BeyondHDSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.ApiKey).NotEmpty();
|
||||
RuleFor(c => c.RssKey).NotEmpty();
|
||||
RuleFor(c => c.ApiKey).NotEmpty().Length(32);
|
||||
RuleFor(c => c.RssKey).NotEmpty().Length(32);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,22 +39,22 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
|
||||
|
||||
var indexerLogging = _configService.LogIndexerResponse;
|
||||
|
||||
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
|
||||
if (indexerResponse.HttpResponse.HasHttpRedirect && indexerResponse.HttpResponse.RedirectUrl.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
if (indexerResponse.HttpResponse.HasHttpRedirect)
|
||||
_logger.Warn("Redirected to {0} from indexer request", indexerResponse.HttpResponse.RedirectUrl);
|
||||
|
||||
if (indexerResponse.HttpResponse.RedirectUrl.ContainsIgnoreCase("/login.php"))
|
||||
{
|
||||
_logger.Warn("Redirected to {0} from indexer request", indexerResponse.HttpResponse.RedirectUrl);
|
||||
|
||||
if (indexerResponse.HttpResponse.RedirectUrl.ContainsIgnoreCase("/login.php"))
|
||||
{
|
||||
// Remove cookie cache
|
||||
CookiesUpdater(null, null);
|
||||
throw new IndexerException(indexerResponse, "We are being redirected to the login page. Most likely your session expired or was killed. Recheck your cookie or credentials and try testing the indexer.");
|
||||
}
|
||||
|
||||
throw new IndexerException(indexerResponse, $"Redirected to {indexerResponse.HttpResponse.RedirectUrl} from indexer request");
|
||||
// Remove cookie cache
|
||||
CookiesUpdater(null, null);
|
||||
throw new IndexerException(indexerResponse, "We are being redirected to the login page. Most likely your session expired or was killed. Recheck your cookie or credentials and try testing the indexer.");
|
||||
}
|
||||
|
||||
throw new IndexerException(indexerResponse, $"Redirected to {indexerResponse.HttpResponse.RedirectUrl} from indexer request");
|
||||
}
|
||||
|
||||
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request");
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ public class FileListParser : IParseIndexerResponse
|
||||
InfoUrl = GetInfoUrl(id),
|
||||
Seeders = row.Seeders,
|
||||
Peers = row.Leechers + row.Seeders,
|
||||
PublishDate = DateTime.Parse(row.UploadDate + " +0300", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal),
|
||||
PublishDate = DateTime.Parse(row.UploadDate + " +0200", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal),
|
||||
Description = row.SmallDescription,
|
||||
Genres = row.SmallDescription.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList(),
|
||||
ImdbId = imdbId,
|
||||
|
||||
@@ -189,7 +189,7 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
|
||||
var qc = new NameValueCollection();
|
||||
|
||||
foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories))
|
||||
foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories).Distinct())
|
||||
{
|
||||
qc.Add(cat, string.Empty);
|
||||
}
|
||||
@@ -203,10 +203,13 @@ namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
// ipt uses sphinx, which supports boolean operators and grouping
|
||||
qc.Add("q", "+(" + imdbId + ")");
|
||||
|
||||
// search in description
|
||||
qc.Add("qf", "all");
|
||||
}
|
||||
|
||||
// changed from else if to if to support searching imdbid + season/episode in the same query
|
||||
if (!string.IsNullOrWhiteSpace(term))
|
||||
// changed from "else if" to "if" to support searching imdbid + season/episode in the same query
|
||||
if (term.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
// similar to above
|
||||
qc.Add("q", "+(" + term + ")");
|
||||
|
||||
348
src/NzbDrone.Core/Indexers/Definitions/Knaben.cs
Normal file
348
src/NzbDrone.Core/Indexers/Definitions/Knaben.cs
Normal file
@@ -0,0 +1,348 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Exceptions;
|
||||
using NzbDrone.Core.Indexers.Settings;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using static Newtonsoft.Json.Formatting;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
public class Knaben : TorrentIndexerBase<NoAuthTorrentBaseSettings>
|
||||
{
|
||||
public override string Name => "Knaben";
|
||||
public override string[] IndexerUrls => new[] { "https://knaben.eu/" };
|
||||
public override string Description => "Knaben is a Public torrent meta-search engine";
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
|
||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||
|
||||
public Knaben(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new KnabenRequestGenerator(Capabilities);
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new KnabenParser(Capabilities.Categories);
|
||||
}
|
||||
|
||||
private static IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(1000000, NewznabStandardCategory.Audio, "Audio");
|
||||
caps.Categories.AddCategoryMapping(1001000, NewznabStandardCategory.AudioMP3, "MP3");
|
||||
caps.Categories.AddCategoryMapping(1002000, NewznabStandardCategory.AudioLossless, "Lossless");
|
||||
caps.Categories.AddCategoryMapping(1003000, NewznabStandardCategory.AudioAudiobook, "Audiobook");
|
||||
caps.Categories.AddCategoryMapping(1004000, NewznabStandardCategory.AudioVideo, "Audio Video");
|
||||
caps.Categories.AddCategoryMapping(1005000, NewznabStandardCategory.AudioOther, "Radio");
|
||||
caps.Categories.AddCategoryMapping(1006000, NewznabStandardCategory.AudioOther, "Audio Other");
|
||||
caps.Categories.AddCategoryMapping(2000000, NewznabStandardCategory.TV, "TV");
|
||||
caps.Categories.AddCategoryMapping(2001000, NewznabStandardCategory.TVHD, "TV HD");
|
||||
caps.Categories.AddCategoryMapping(2002000, NewznabStandardCategory.TVSD, "TV SD");
|
||||
caps.Categories.AddCategoryMapping(2003000, NewznabStandardCategory.TVUHD, "TV UHD");
|
||||
caps.Categories.AddCategoryMapping(2004000, NewznabStandardCategory.TVDocumentary, "Documentary");
|
||||
caps.Categories.AddCategoryMapping(2005000, NewznabStandardCategory.TVForeign, "TV Foreign");
|
||||
caps.Categories.AddCategoryMapping(2006000, NewznabStandardCategory.TVSport, "Sport");
|
||||
caps.Categories.AddCategoryMapping(2007000, NewznabStandardCategory.TVOther, "Cartoon");
|
||||
caps.Categories.AddCategoryMapping(2008000, NewznabStandardCategory.TVOther, "TV Other");
|
||||
caps.Categories.AddCategoryMapping(3000000, NewznabStandardCategory.Movies, "Movies");
|
||||
caps.Categories.AddCategoryMapping(3001000, NewznabStandardCategory.MoviesHD, "Movies HD");
|
||||
caps.Categories.AddCategoryMapping(3002000, NewznabStandardCategory.MoviesSD, "Movies SD");
|
||||
caps.Categories.AddCategoryMapping(3003000, NewznabStandardCategory.MoviesUHD, "Movies UHD");
|
||||
caps.Categories.AddCategoryMapping(3004000, NewznabStandardCategory.MoviesDVD, "Movies DVD");
|
||||
caps.Categories.AddCategoryMapping(3005000, NewznabStandardCategory.MoviesForeign, "Movies Foreign");
|
||||
caps.Categories.AddCategoryMapping(3006000, NewznabStandardCategory.MoviesForeign, "Movies Bollywood");
|
||||
caps.Categories.AddCategoryMapping(3007000, NewznabStandardCategory.Movies3D, "Movies 3D");
|
||||
caps.Categories.AddCategoryMapping(3008000, NewznabStandardCategory.MoviesOther, "Movies Other");
|
||||
caps.Categories.AddCategoryMapping(4000000, NewznabStandardCategory.PC, "PC");
|
||||
caps.Categories.AddCategoryMapping(4001000, NewznabStandardCategory.PCGames, "Games");
|
||||
caps.Categories.AddCategoryMapping(4002000, NewznabStandardCategory.PC0day, "Software");
|
||||
caps.Categories.AddCategoryMapping(4003000, NewznabStandardCategory.PCMac, "Mac");
|
||||
caps.Categories.AddCategoryMapping(4004000, NewznabStandardCategory.PCISO, "Unix");
|
||||
caps.Categories.AddCategoryMapping(5000000, NewznabStandardCategory.XXX, "XXX");
|
||||
caps.Categories.AddCategoryMapping(5001000, NewznabStandardCategory.XXXx264, "XXX Video");
|
||||
caps.Categories.AddCategoryMapping(5002000, NewznabStandardCategory.XXXImageSet, "XXX ImageSet");
|
||||
caps.Categories.AddCategoryMapping(5003000, NewznabStandardCategory.XXXOther, "XXX Games");
|
||||
caps.Categories.AddCategoryMapping(5004000, NewznabStandardCategory.XXXOther, "XXX Hentai");
|
||||
caps.Categories.AddCategoryMapping(5005000, NewznabStandardCategory.XXXOther, "XXX Other");
|
||||
caps.Categories.AddCategoryMapping(6000000, NewznabStandardCategory.TVAnime, "Anime");
|
||||
caps.Categories.AddCategoryMapping(6001000, NewznabStandardCategory.TVAnime, "Anime Subbed");
|
||||
caps.Categories.AddCategoryMapping(6002000, NewznabStandardCategory.TVAnime, "Anime Dubbed");
|
||||
caps.Categories.AddCategoryMapping(6003000, NewznabStandardCategory.TVAnime, "Anime Dual audio");
|
||||
caps.Categories.AddCategoryMapping(6004000, NewznabStandardCategory.TVAnime, "Anime Raw");
|
||||
caps.Categories.AddCategoryMapping(6005000, NewznabStandardCategory.AudioVideo, "Music Video");
|
||||
caps.Categories.AddCategoryMapping(6006000, NewznabStandardCategory.BooksOther, "Literature");
|
||||
caps.Categories.AddCategoryMapping(6007000, NewznabStandardCategory.AudioOther, "Music");
|
||||
caps.Categories.AddCategoryMapping(6008000, NewznabStandardCategory.TVAnime, "Anime non-english translated");
|
||||
caps.Categories.AddCategoryMapping(7000000, NewznabStandardCategory.Console, "Console");
|
||||
caps.Categories.AddCategoryMapping(7001000, NewznabStandardCategory.ConsolePS4, "PS4");
|
||||
caps.Categories.AddCategoryMapping(7002000, NewznabStandardCategory.ConsolePS3, "PS3");
|
||||
caps.Categories.AddCategoryMapping(7003000, NewznabStandardCategory.ConsolePS3, "PS2");
|
||||
caps.Categories.AddCategoryMapping(7004000, NewznabStandardCategory.ConsolePS3, "PS1");
|
||||
caps.Categories.AddCategoryMapping(7005000, NewznabStandardCategory.ConsolePSVita, "PS Vita");
|
||||
caps.Categories.AddCategoryMapping(7006000, NewznabStandardCategory.ConsolePSP, "PSP");
|
||||
caps.Categories.AddCategoryMapping(7007000, NewznabStandardCategory.ConsoleXBox360, "Xbox 360");
|
||||
caps.Categories.AddCategoryMapping(7008000, NewznabStandardCategory.ConsoleXBox, "Xbox");
|
||||
caps.Categories.AddCategoryMapping(7009000, NewznabStandardCategory.ConsoleNDS, "Switch");
|
||||
caps.Categories.AddCategoryMapping(7010000, NewznabStandardCategory.ConsoleNDS, "NDS");
|
||||
caps.Categories.AddCategoryMapping(7011000, NewznabStandardCategory.ConsoleWii, "Wii");
|
||||
caps.Categories.AddCategoryMapping(7012000, NewznabStandardCategory.ConsoleWiiU, "WiiU");
|
||||
caps.Categories.AddCategoryMapping(7013000, NewznabStandardCategory.Console3DS, "3DS");
|
||||
caps.Categories.AddCategoryMapping(7014000, NewznabStandardCategory.ConsoleWii, "GameCube");
|
||||
caps.Categories.AddCategoryMapping(7015000, NewznabStandardCategory.ConsoleOther, "Other");
|
||||
caps.Categories.AddCategoryMapping(8000000, NewznabStandardCategory.PCMobileOther, "Mobile");
|
||||
caps.Categories.AddCategoryMapping(8001000, NewznabStandardCategory.PCMobileAndroid, "Android");
|
||||
caps.Categories.AddCategoryMapping(8002000, NewznabStandardCategory.PCMobileiOS, "IOS");
|
||||
caps.Categories.AddCategoryMapping(8003000, NewznabStandardCategory.PCMobileOther, "PC Other");
|
||||
caps.Categories.AddCategoryMapping(9000000, NewznabStandardCategory.Books, "Books");
|
||||
caps.Categories.AddCategoryMapping(9001000, NewznabStandardCategory.BooksEBook, "EBooks");
|
||||
caps.Categories.AddCategoryMapping(9002000, NewznabStandardCategory.BooksComics, "Comics");
|
||||
caps.Categories.AddCategoryMapping(9003000, NewznabStandardCategory.BooksMags, "Magazines");
|
||||
caps.Categories.AddCategoryMapping(9004000, NewznabStandardCategory.BooksTechnical, "Technical");
|
||||
caps.Categories.AddCategoryMapping(9005000, NewznabStandardCategory.BooksOther, "Books Other");
|
||||
caps.Categories.AddCategoryMapping(10000000, NewznabStandardCategory.Other, "Other");
|
||||
caps.Categories.AddCategoryMapping(10001000, NewznabStandardCategory.OtherMisc, "Other Misc");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class KnabenRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
private const string API_SEARCH_ENDPOINT = "https://api.knaben.eu/v1";
|
||||
|
||||
private readonly IndexerCapabilities _capabilities;
|
||||
|
||||
public KnabenRequestGenerator(IndexerCapabilities capabilities)
|
||||
{
|
||||
_capabilities = capabilities;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(CreateRequest(searchCriteria, searchCriteria.SanitizedSearchTerm));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(CreateRequest(searchCriteria, searchCriteria.SanitizedSearchTerm));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(CreateRequest(searchCriteria, searchCriteria.SanitizedTvSearchString));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(CreateRequest(searchCriteria, searchCriteria.SanitizedSearchTerm));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(CreateRequest(searchCriteria, searchCriteria.SanitizedSearchTerm));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> CreateRequest(SearchCriteriaBase searchCriteria, string searchTerm)
|
||||
{
|
||||
var body = new Dictionary<string, object>
|
||||
{
|
||||
{ "order_by", "date" },
|
||||
{ "order_direction", "desc" },
|
||||
{ "from", 0 },
|
||||
{ "size", 100 },
|
||||
{ "hide_unsafe", true }
|
||||
};
|
||||
|
||||
var searchQuery = searchTerm.Trim();
|
||||
|
||||
if (searchQuery.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
body.Add("search_type", "100%");
|
||||
body.Add("search_field", "title");
|
||||
body.Add("query", searchQuery);
|
||||
}
|
||||
|
||||
var categories = _capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories);
|
||||
|
||||
if (categories is { Count: > 0 })
|
||||
{
|
||||
body.Add("categories", categories.Select(int.Parse).Distinct().ToArray());
|
||||
}
|
||||
|
||||
var request = new HttpRequest(API_SEARCH_ENDPOINT, HttpAccept.Json)
|
||||
{
|
||||
Headers =
|
||||
{
|
||||
ContentType = "application/json"
|
||||
},
|
||||
Method = HttpMethod.Post
|
||||
};
|
||||
request.SetContent(body.ToJson());
|
||||
request.ContentSummary = body.ToJson(None);
|
||||
|
||||
yield return new IndexerRequest(request);
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class KnabenParser : IParseIndexerResponse
|
||||
{
|
||||
private static readonly Regex DateTimezoneRegex = new (@"[+-]\d{2}:\d{2}$", RegexOptions.Compiled);
|
||||
|
||||
private readonly IndexerCapabilitiesCategories _categories;
|
||||
|
||||
public KnabenParser(IndexerCapabilitiesCategories categories)
|
||||
{
|
||||
_categories = categories;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var indexerHttpResponse = indexerResponse.HttpResponse;
|
||||
|
||||
if (indexerHttpResponse.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerHttpResponse.StatusCode} code from indexer request");
|
||||
}
|
||||
|
||||
if (!indexerHttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
|
||||
{
|
||||
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerHttpResponse.Headers.ContentType} from indexer request, expected {HttpAccept.Json.Value}");
|
||||
}
|
||||
|
||||
var releaseInfos = new List<ReleaseInfo>();
|
||||
|
||||
var jsonResponse = STJson.Deserialize<KnabenResponse>(indexerResponse.Content);
|
||||
|
||||
if (jsonResponse?.Hits == null)
|
||||
{
|
||||
return releaseInfos;
|
||||
}
|
||||
|
||||
var rows = jsonResponse.Hits.Where(r => r.Seeders > 0).ToList();
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
// Not all entries have the TZ in the "date" field
|
||||
var publishDate = row.Date.IsNotNullOrWhiteSpace() && !DateTimezoneRegex.IsMatch(row.Date) ? $"{row.Date}+01:00" : row.Date;
|
||||
|
||||
var releaseInfo = new TorrentInfo
|
||||
{
|
||||
Guid = row.InfoUrl,
|
||||
Title = row.Title,
|
||||
InfoUrl = row.InfoUrl,
|
||||
DownloadUrl = row.DownloadUrl.IsNotNullOrWhiteSpace() ? row.DownloadUrl : null,
|
||||
MagnetUrl = row.MagnetUrl.IsNotNullOrWhiteSpace() ? row.MagnetUrl : null,
|
||||
Categories = row.CategoryIds.SelectMany(cat => _categories.MapTrackerCatToNewznab(cat.ToString())).Distinct().ToList(),
|
||||
InfoHash = row.InfoHash,
|
||||
Size = row.Size,
|
||||
Seeders = row.Seeders,
|
||||
Peers = row.Leechers + row.Seeders,
|
||||
PublishDate = DateTime.Parse(publishDate, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal),
|
||||
DownloadVolumeFactor = 0,
|
||||
UploadVolumeFactor = 1
|
||||
};
|
||||
|
||||
releaseInfos.Add(releaseInfo);
|
||||
}
|
||||
|
||||
// order by date
|
||||
return releaseInfos;
|
||||
}
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class KnabenResponse
|
||||
{
|
||||
public IReadOnlyCollection<KnabenRelease> Hits { get; init; } = Array.Empty<KnabenRelease>();
|
||||
}
|
||||
|
||||
internal sealed class KnabenRelease
|
||||
{
|
||||
public string Title { get; init; }
|
||||
|
||||
[JsonPropertyName("categoryId")]
|
||||
public IReadOnlyCollection<int> CategoryIds { get; init; } = Array.Empty<int>();
|
||||
|
||||
[JsonPropertyName("hash")]
|
||||
public string InfoHash { get; init; }
|
||||
|
||||
[JsonPropertyName("details")]
|
||||
public string InfoUrl { get; init; }
|
||||
|
||||
[JsonPropertyName("link")]
|
||||
public string DownloadUrl { get; init; }
|
||||
|
||||
public string MagnetUrl { get; init; }
|
||||
|
||||
[JsonPropertyName("bytes")]
|
||||
public long Size { get; init; }
|
||||
|
||||
public int Seeders { get; init; }
|
||||
|
||||
[JsonPropertyName("peers")]
|
||||
public int Leechers { get; init; }
|
||||
|
||||
public string Date { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Site has removed API access.")]
|
||||
public class NzbIndex : UsenetIndexerBase<NzbIndexSettings>
|
||||
{
|
||||
public override string Name => "NZBIndex";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using MonoTorrent;
|
||||
using NLog;
|
||||
@@ -22,10 +23,10 @@ namespace NzbDrone.Core.Indexers
|
||||
{
|
||||
Torrent.Load(fileData);
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Debug("Invalid torrent file contents: {0}", Encoding.ASCII.GetString(fileData));
|
||||
throw;
|
||||
throw new NotSupportedException($"Invalid torrent file contents. Reason: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,33 +60,36 @@ namespace NzbDrone.Core.Instrumentation
|
||||
{
|
||||
try
|
||||
{
|
||||
var log = new Log();
|
||||
log.Time = logEvent.TimeStamp;
|
||||
log.Message = CleanseLogMessage.Cleanse(logEvent.FormattedMessage);
|
||||
|
||||
log.Logger = logEvent.LoggerName;
|
||||
var log = new Log
|
||||
{
|
||||
Time = logEvent.TimeStamp,
|
||||
Logger = logEvent.LoggerName,
|
||||
Level = logEvent.Level.Name
|
||||
};
|
||||
|
||||
if (log.Logger.StartsWith("NzbDrone."))
|
||||
{
|
||||
log.Logger = log.Logger.Remove(0, 9);
|
||||
}
|
||||
|
||||
var message = logEvent.FormattedMessage;
|
||||
|
||||
if (logEvent.Exception != null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(log.Message))
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
log.Message = logEvent.Exception.Message;
|
||||
message = logEvent.Exception.Message;
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Message += ": " + logEvent.Exception.Message;
|
||||
message += ": " + logEvent.Exception.Message;
|
||||
}
|
||||
|
||||
log.Exception = logEvent.Exception.ToString();
|
||||
log.Exception = CleanseLogMessage.Cleanse(logEvent.Exception.ToString());
|
||||
log.ExceptionType = logEvent.Exception.GetType().ToString();
|
||||
}
|
||||
|
||||
log.Level = logEvent.Level.Name;
|
||||
log.Message = CleanseLogMessage.Cleanse(message);
|
||||
|
||||
var connectionInfo = _connectionStringFactory.LogDbConnection;
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace NzbDrone.Core.Jobs
|
||||
new ScheduledTask
|
||||
{
|
||||
Interval = 6 * 60,
|
||||
TypeName = typeof(ApplicationCheckUpdateCommand).FullName
|
||||
TypeName = typeof(ApplicationUpdateCheckCommand).FullName
|
||||
},
|
||||
|
||||
new ScheduledTask
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"UnableToAddANewAppProfilePleaseTryAgain": "غير قادر على إضافة ملف تعريف جودة جديد ، يرجى المحاولة مرة أخرى.",
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "غير قادر على إضافة عميل تنزيل جديد ، يرجى المحاولة مرة أخرى.",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "غير قادر على إضافة مفهرس جديد ، يرجى المحاولة مرة أخرى.",
|
||||
"UnableToLoadBackups": "تعذر تحميل النسخ الاحتياطية",
|
||||
"BackupsLoadError": "تعذر تحميل النسخ الاحتياطية",
|
||||
"UnsavedChanges": "التغييرات غير المحفوظة",
|
||||
"UpdateUiNotWritableHealthCheckMessage": "لا يمكن تثبيت التحديث لأن مجلد واجهة المستخدم '{uiFolder}' غير قابل للكتابة بواسطة المستخدم '{userName}'",
|
||||
"UpdateScriptPathHelpText": "المسار إلى برنامج نصي مخصص يأخذ حزمة تحديث مستخرجة ويتعامل مع ما تبقى من عملية التحديث",
|
||||
@@ -329,7 +329,7 @@
|
||||
"Queued": "في قائمة الانتظار",
|
||||
"Remove": "إزالة",
|
||||
"Replace": "يحل محل",
|
||||
"TheLatestVersionIsAlreadyInstalled": "تم بالفعل تثبيت أحدث إصدار من {0}",
|
||||
"OnLatestVersion": "تم بالفعل تثبيت أحدث إصدار من {0}",
|
||||
"DownloadClientPriorityHelpText": "تحديد أولويات عملاء التنزيل المتعددين. يتم استخدام Round-Robin للعملاء الذين لديهم نفس الأولوية.",
|
||||
"ApplyTagsHelpTextAdd": "إضافة: أضف العلامات إلى قائمة العلامات الموجودة",
|
||||
"ApplyTagsHelpTextHowToApplyApplications": "كيفية تطبيق العلامات على الأفلام المختارة",
|
||||
@@ -361,5 +361,14 @@
|
||||
"Script": "النصي",
|
||||
"BuiltIn": "مدمج",
|
||||
"PublishedDate": "تاريخ النشر",
|
||||
"AllSearchResultsHiddenByFilter": "يتم إخفاء جميع النتائج بواسطة عامل التصفية المطبق"
|
||||
"AllSearchResultsHiddenByFilter": "يتم إخفاء جميع النتائج بواسطة عامل التصفية المطبق",
|
||||
"NoEventsFound": "لم يتم العثور على أحداث",
|
||||
"RestartReloadNote": "ملاحظة: سيتم إعادة تشغيل {appName} تلقائيًا وإعادة تحميل واجهة المستخدم أثناء عملية الاستعادة.",
|
||||
"UpdateAppDirectlyLoadError": "تعذر تحديث {appName} مباشرة ،",
|
||||
"DockerUpdater": "تحديث حاوية عامل الإرساء لتلقي التحديث",
|
||||
"Download": "تحميل",
|
||||
"ErrorRestoringBackup": "خطأ في استعادة النسخة الاحتياطية",
|
||||
"ExternalUpdater": "تم تكوين {appName} لاستخدام آلية تحديث خارجية",
|
||||
"InstallLatest": "تثبيت الأحدث",
|
||||
"AptUpdater": "استخدم apt لتثبيت التحديث"
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
"UISettings": "Настройки на потребителския интерфейс",
|
||||
"UnableToAddANewApplicationPleaseTryAgain": "Не може да се добави ново известие, моля, опитайте отново.",
|
||||
"UnableToAddANewAppProfilePleaseTryAgain": "Не може да се добави нов качествен профил, моля, опитайте отново.",
|
||||
"UnableToLoadBackups": "Архивите не могат да се заредят",
|
||||
"BackupsLoadError": "Архивите не могат да се заредят",
|
||||
"AllIndexersHiddenDueToFilter": "Всички филми са скрити поради приложен филтър.",
|
||||
"Level": "Ниво",
|
||||
"ApplicationStatusCheckAllClientMessage": "Всички списъци са недостъпни поради неуспехи",
|
||||
@@ -329,7 +329,7 @@
|
||||
"Queued": "На опашка",
|
||||
"Remove": "Премахване",
|
||||
"Replace": "Сменете",
|
||||
"TheLatestVersionIsAlreadyInstalled": "Вече е инсталирана най-новата версия на {0}",
|
||||
"OnLatestVersion": "Вече е инсталирана най-новата версия на {0}",
|
||||
"Genre": "Жанрове",
|
||||
"ApplyTagsHelpTextRemove": "Премахване: Премахнете въведените тагове",
|
||||
"ApplyTagsHelpTextHowToApplyIndexers": "Как да приложите тагове към избраните филми",
|
||||
@@ -361,5 +361,14 @@
|
||||
"BuiltIn": "Вграден",
|
||||
"Script": "Сценарий",
|
||||
"PublishedDate": "Дата на публикуване",
|
||||
"AllSearchResultsHiddenByFilter": "Всички резултати са скрити от приложения филтър"
|
||||
"AllSearchResultsHiddenByFilter": "Всички резултати са скрити от приложения филтър",
|
||||
"DockerUpdater": "актуализирайте контейнера на докера, за да получите актуализацията",
|
||||
"Download": "Изтегли",
|
||||
"ErrorRestoringBackup": "Грешка при възстановяване на архивиране",
|
||||
"ExternalUpdater": "{appName} е конфигуриран да използва външен механизъм за актуализация",
|
||||
"NoEventsFound": "Няма намерени събития",
|
||||
"RestartReloadNote": "Забележка: {appName} автоматично ще рестартира и презареди потребителския интерфейс по време на процеса на възстановяване.",
|
||||
"UpdateAppDirectlyLoadError": "Не може да се актуализира {appName} директно,",
|
||||
"AptUpdater": "Използвайте apt, за да инсталирате актуализацията",
|
||||
"InstallLatest": "Инсталирайте най-новите"
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"Type": "Tipus",
|
||||
"UILanguageHelpTextWarning": "Es requereix una recàrrega del navegador",
|
||||
"UISettings": "Configuració de la interfície",
|
||||
"UnableToLoadBackups": "No es poden carregar còpies de seguretat",
|
||||
"BackupsLoadError": "No es poden carregar còpies de seguretat",
|
||||
"DownloadClientsLoadError": "No es poden carregar els clients de baixada",
|
||||
"UnableToLoadTags": "No es poden carregar les etiquetes",
|
||||
"UnableToLoadUISettings": "No es pot carregar la configuració de la IU",
|
||||
@@ -340,7 +340,7 @@
|
||||
"UILanguageHelpText": "Idioma que utilitzarà {appName} per a la interfície d'usuari",
|
||||
"Remove": "Elimina",
|
||||
"Replace": "Substitueix",
|
||||
"TheLatestVersionIsAlreadyInstalled": "La darrera versió de {appName} ja està instal·lada",
|
||||
"OnLatestVersion": "La darrera versió de {appName} ja està instal·lada",
|
||||
"ThemeHelpText": "Canvieu el tema de la interfície d'usuari de l'aplicació, el tema \"Automàtic\" utilitzarà el tema del vostre sistema operatiu per configurar el mode clar o fosc. Inspirat en {inspiredBy}.",
|
||||
"ApplicationURL": "URL de l'aplicació",
|
||||
"Publisher": "Editor",
|
||||
@@ -485,5 +485,19 @@
|
||||
"PublishedDate": "Data de publicació",
|
||||
"Redirected": "Redirecció",
|
||||
"AllSearchResultsHiddenByFilter": "Tots els resultats estan ocults pel filtre aplicat",
|
||||
"HealthMessagesInfoBox": "Podeu trobar més informació sobre la causa d'aquests missatges de comprovació de salut fent clic a l'enllaç wiki (icona del llibre) al final de la fila o consultant els vostres [registres]({link}). Si teniu problemes per a interpretar aquests missatges, podeu posar-vos en contacte amb el nostre suport als enllaços següents."
|
||||
"HealthMessagesInfoBox": "Podeu trobar més informació sobre la causa d'aquests missatges de comprovació de salut fent clic a l'enllaç wiki (icona del llibre) al final de la fila o consultant els vostres [registres]({link}). Si teniu problemes per a interpretar aquests missatges, podeu posar-vos en contacte amb el nostre suport als enllaços següents.",
|
||||
"AptUpdater": "Utilitzeu apt per a instal·lar l'actualització",
|
||||
"DockerUpdater": "actualitzeu el contenidor Docker per a rebre l'actualització",
|
||||
"Download": "Baixa",
|
||||
"ErrorRestoringBackup": "S'ha produït un error en restaurar la còpia de seguretat",
|
||||
"ExternalUpdater": "{appName} està configurat per a utilitzar un mecanisme d'actualització extern",
|
||||
"FailedToFetchUpdates": "No s'han pogut obtenir les actualitzacions",
|
||||
"LogFilesLocation": "Els fitxers de registre es troben a: {location}",
|
||||
"Logout": "Tanca la sessió",
|
||||
"NoEventsFound": "No s'han trobat esdeveniments",
|
||||
"RestartReloadNote": "Nota: {appName} es reiniciarà i tornarà a carregar automàticament la interfície d'usuari durant el procés de restauració.",
|
||||
"TheLogLevelDefault": "El nivell de registre per defecte és \"Info\" i es pot canviar a [Configuració general](/configuració/general)",
|
||||
"UpdateAppDirectlyLoadError": "No es pot actualitzar {appName} directament,",
|
||||
"WouldYouLikeToRestoreBackup": "Voleu restaurar la còpia de seguretat '{name}'?",
|
||||
"InstallLatest": "Instal·la l'últim"
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
"SSLCertPasswordHelpText": "Heslo pro soubor pfx",
|
||||
"SSLCertPath": "Cesta certifikátu SSL",
|
||||
"SSLCertPathHelpText": "Cesta k souboru pfx",
|
||||
"UnableToLoadBackups": "Nelze načíst zálohy",
|
||||
"BackupsLoadError": "Nelze načíst zálohy",
|
||||
"DownloadClientsLoadError": "Nelze načíst klienty pro stahování",
|
||||
"UnableToLoadGeneralSettings": "Nelze načíst obecná nastavení",
|
||||
"DeleteNotification": "Smazat oznámení",
|
||||
@@ -329,7 +329,7 @@
|
||||
"Queued": "Ve frontě",
|
||||
"Remove": "Odstranit",
|
||||
"Replace": "Nahradit",
|
||||
"TheLatestVersionIsAlreadyInstalled": "Nejnovější verze aplikace {appName} je již nainstalována",
|
||||
"OnLatestVersion": "Nejnovější verze aplikace {appName} je již nainstalována",
|
||||
"More": "Více",
|
||||
"ApplyTagsHelpTextAdd": "Přidat: Přidá značky k již existujícímu seznamu",
|
||||
"ApplyTagsHelpTextHowToApplyApplications": "Jak použít značky na vybrané filmy",
|
||||
@@ -423,5 +423,15 @@
|
||||
"BuiltIn": "Vestavěný",
|
||||
"Script": "Skript",
|
||||
"PublishedDate": "Datum zveřejnění",
|
||||
"AllSearchResultsHiddenByFilter": "Všechny výsledky jsou schovány použitým filtrem"
|
||||
"AllSearchResultsHiddenByFilter": "Všechny výsledky jsou schovány použitým filtrem",
|
||||
"DockerUpdater": "aktualizujte kontejner dockeru, abyste aktualizaci obdrželi",
|
||||
"Download": "Stažení",
|
||||
"ErrorRestoringBackup": "Chyba při obnovování zálohy",
|
||||
"ExternalUpdater": "{appName} je nakonfigurován pro použití externího aktualizačního mechanismu",
|
||||
"FailedToFetchUpdates": "Nepodařilo se načíst aktualizace",
|
||||
"NoEventsFound": "Nebyly nalezeny žádné události",
|
||||
"RestartReloadNote": "Poznámka: {appName} se během procesu obnovy automaticky restartuje a znovu načte uživatelské rozhraní.",
|
||||
"UpdateAppDirectlyLoadError": "{appName} nelze aktualizovat přímo,",
|
||||
"AptUpdater": "K instalaci aktualizace použijte apt",
|
||||
"InstallLatest": "Nainstalujte nejnovější"
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@
|
||||
"UnableToAddANewAppProfilePleaseTryAgain": "Kan ikke tilføje en ny kvalitetsprofil, prøv igen.",
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "Kunne ikke tilføje en ny downloadklient. Prøv igen.",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "Kunne ikke tilføje en ny indekser. Prøv igen.",
|
||||
"UnableToLoadBackups": "Kunne ikke indlæse sikkerhedskopier",
|
||||
"BackupsLoadError": "Kunne ikke indlæse sikkerhedskopier",
|
||||
"UnableToLoadGeneralSettings": "Kan ikke indlæse generelle indstillinger",
|
||||
"UnableToLoadNotifications": "Kunne ikke indlæse meddelelser",
|
||||
"UnableToLoadTags": "Kan ikke indlæse tags",
|
||||
@@ -340,7 +340,7 @@
|
||||
"Notification": "Notifikationer",
|
||||
"Remove": "Fjerne",
|
||||
"Replace": "erstat",
|
||||
"TheLatestVersionIsAlreadyInstalled": "Den seneste version af {appName} er allerede installeret",
|
||||
"OnLatestVersion": "Den seneste version af {appName} er allerede installeret",
|
||||
"Year": "År",
|
||||
"ApplyTagsHelpTextAdd": "Tilføj: Føj tags til den eksisterende liste over tags",
|
||||
"ApplyTagsHelpTextHowToApplyApplications": "Sådan anvendes tags på de valgte film",
|
||||
@@ -401,5 +401,14 @@
|
||||
"AllSearchResultsHiddenByFilter": "Alle resultater skjules af det anvendte filter",
|
||||
"AddApplication": "Tilføj Applikation",
|
||||
"AddCategory": "Tilføj Kategori",
|
||||
"ActiveApps": "Aktive Apps"
|
||||
"ActiveApps": "Aktive Apps",
|
||||
"NoEventsFound": "Ingen begivenheder fundet",
|
||||
"AptUpdater": "Brug apt til at installere opdateringen",
|
||||
"DockerUpdater": "opdater docker-containeren for at modtage opdateringen",
|
||||
"Download": "Hent",
|
||||
"ErrorRestoringBackup": "Fejl ved gendannelse af sikkerhedskopi",
|
||||
"ExternalUpdater": "{appName} er konfigureret til at bruge en ekstern opdateringsmekanisme",
|
||||
"RestartReloadNote": "Bemærk: {appName} genstarter automatisk og genindlæser brugergrænsefladen under gendannelsesprocessen.",
|
||||
"UpdateAppDirectlyLoadError": "Kan ikke opdatere {appName} direkte,",
|
||||
"InstallLatest": "Installer senest"
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@
|
||||
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Alle Indexer sind wegen über 6 Stunden langen bestehender Fehler nicht verfügbar",
|
||||
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Indexer wegen über 6 Stunden langen bestehenden Fehlern nicht verfügbar: {indexerNames}",
|
||||
"IndexerName": "Indexer-Name",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "Indexer haben keine Definition und werden nicht funktionieren: {0}. Bitte entferne und (oder) füge diese neu zu {appName} hinzu",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "Indexer haben keine Definition und werden nicht funktionieren: {indexerNames}. Bitte entferne und (oder) füge diese neu zu {appName} hinzu",
|
||||
"IndexerObsoleteCheckMessage": "Indexer sind nicht mehr verfügbar oder wurden aktualiiert: {0}. Bitte enfernen und (oder) neu zu {appName} hinzufügen",
|
||||
"IndexerPriority": "Priorität",
|
||||
"IndexerPriorityHelpText": "Indexer Priorität von 1 (höchste) bis 50 (niedrigste). Standard: 25.",
|
||||
@@ -394,7 +394,7 @@
|
||||
"TestAllApps": "Alle Apps testen",
|
||||
"TestAllClients": "Prüfe alle Clients",
|
||||
"TestAllIndexers": "Prüfe alle Indexer",
|
||||
"TheLatestVersionIsAlreadyInstalled": "Die aktuellste Version ist bereits installiert",
|
||||
"OnLatestVersion": "Die aktuellste Version ist bereits installiert",
|
||||
"ThemeHelpText": "Ändere das UI-Theme der Anwendung. Das 'Auto'-Theme verwendet dein Betriebssystem-Theme, um den hellen oder dunklen Modus einzustellen. Inspiriert von {0}",
|
||||
"Time": "Zeit",
|
||||
"Title": "Titel",
|
||||
@@ -419,7 +419,7 @@
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Die neue Benachrichtigung konnte nicht hinzugefügt werden, bitte erneut probieren.",
|
||||
"UnableToLoadAppProfiles": "App-Profile können nicht geladen werden",
|
||||
"ApplicationsLoadError": "Anwendungsliste kann nicht geladen werden",
|
||||
"UnableToLoadBackups": "Sicherungen können nicht geladen werden",
|
||||
"BackupsLoadError": "Sicherungen können nicht geladen werden",
|
||||
"UnableToLoadDevelopmentSettings": "Entwicklereinstellungen konnten nicht geladen werden",
|
||||
"DownloadClientsLoadError": "Downloader konnten nicht geladen werden",
|
||||
"UnableToLoadGeneralSettings": "Allgemeine Einstellungen konnten nicht geladen werden",
|
||||
@@ -612,5 +612,17 @@
|
||||
"BuiltIn": "Eingebaut",
|
||||
"PublishedDate": "Veröffentlichungsdatum",
|
||||
"Redirected": "Umleiten",
|
||||
"AllSearchResultsHiddenByFilter": "Alle Ergebnisse werden durch den angewendeten Filter ausgeblendet"
|
||||
"AllSearchResultsHiddenByFilter": "Alle Ergebnisse werden durch den angewendeten Filter ausgeblendet",
|
||||
"DockerUpdater": "Aktualisieren Sie den Docker-Container, um das Update zu erhalten",
|
||||
"Download": "Herunterladen",
|
||||
"ErrorRestoringBackup": "Fehler beim Wiederherstellen",
|
||||
"ExternalUpdater": "{appName} wurde so konfiguriert, dass ein externer Update Mechanismus benutzt wird",
|
||||
"NoEventsFound": "Keine Events gefunden",
|
||||
"RestartReloadNote": "Hinweis: {appName} startet während des Wiederherstellungsvorgangs automatisch neu und lädt die Benutzeroberfläche neu.",
|
||||
"TheLogLevelDefault": "Die Protokollebene ist standardmäßig auf „Info“ eingestellt und kann unter „Allgemeine Einstellungen“ (/settings/general) geändert werden.",
|
||||
"UpdateAppDirectlyLoadError": "{appName} kann nicht direkt aktualisiert werden.",
|
||||
"UpdaterLogFiles": "Updater-Protokolldateien",
|
||||
"WouldYouLikeToRestoreBackup": "Willst du das Backup '{name}' wiederherstellen?",
|
||||
"AptUpdater": "Verwenden Sie apt, um das Update zu installieren",
|
||||
"InstallLatest": "Jetzt updaten"
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@
|
||||
"IncludeHealthWarningsHelpText": "Συμπεριλάβετε προειδοποιήσεις για την υγεία",
|
||||
"Security": "Ασφάλεια",
|
||||
"Tasks": "Καθήκοντα",
|
||||
"UnableToLoadBackups": "Δεν είναι δυνατή η φόρτωση αντιγράφων ασφαλείας",
|
||||
"BackupsLoadError": "Δεν είναι δυνατή η φόρτωση αντιγράφων ασφαλείας",
|
||||
"DownloadClientsLoadError": "Δεν είναι δυνατή η φόρτωση πελατών λήψης",
|
||||
"UpdateMechanismHelpText": "Χρησιμοποιήστε το ενσωματωμένο πρόγραμμα ενημέρωσης του {appName} ή ένα script",
|
||||
"AnalyticsEnabledHelpText": "Στείλτε ανώνυμες πληροφορίες χρήσης και σφάλματος στους διακομιστές του {appName}. Αυτό περιλαμβάνει πληροφορίες στο πρόγραμμα περιήγησής σας, ποιες σελίδες {appName} WebUI χρησιμοποιείτε, αναφορά σφαλμάτων καθώς και έκδοση λειτουργικού συστήματος και χρόνου εκτέλεσης. Θα χρησιμοποιήσουμε αυτές τις πληροφορίες για να δώσουμε προτεραιότητα σε λειτουργίες και διορθώσεις σφαλμάτων.",
|
||||
@@ -431,7 +431,7 @@
|
||||
"IndexerInfo": "Πληροφορίες ευρετηρίου",
|
||||
"IndexerName": "Όνομα ευρετηρίου",
|
||||
"IndexerProxies": "Proxer Indexer",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "Τα ευρετήρια δεν έχουν ορισμό και δεν θα λειτουργήσουν: {0}. Αφαιρέστε και (ή) προσθέστε ξανά στο {appName}",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "Τα ευρετήρια δεν έχουν ορισμό και δεν θα λειτουργήσουν: {indexerNames}. Αφαιρέστε και (ή) προσθέστε ξανά στο {appName}",
|
||||
"SemiPrivate": "Ημι-ιδιωτικό",
|
||||
"SettingsIndexerLoggingHelpText": "Καταγραφή πρόσθετων δεδομένων ευρετηρίου συμπεριλαμβανομένης της απόκρισης",
|
||||
"SearchTypes": "Τύποι αναζήτησης",
|
||||
@@ -458,7 +458,7 @@
|
||||
"SyncLevelFull": "Πλήρης συγχρονισμός: Θα διατηρήσει πλήρως συγχρονισμένα τα ευρετήρια αυτής της εφαρμογής. Στη συνέχεια, οι αλλαγές που γίνονται στους indexers στο {appName} συγχρονίζονται με αυτήν την εφαρμογή. Οποιαδήποτε αλλαγή γίνει σε ευρετήρια απομακρυσμένα σε αυτήν την εφαρμογή θα παρακαμφθεί από τον {appName} στον επόμενο συγχρονισμό.",
|
||||
"Remove": "Αφαιρώ",
|
||||
"Replace": "Αντικαθιστώ",
|
||||
"TheLatestVersionIsAlreadyInstalled": "Η τελευταία έκδοση του {appName} είναι ήδη εγκατεστημένη",
|
||||
"OnLatestVersion": "Η τελευταία έκδοση του {appName} είναι ήδη εγκατεστημένη",
|
||||
"ApiKeyValidationHealthCheckMessage": "Παρακαλούμε ενημερώστε το κλείδι API ώστε να έχει τουλάχιστον {length} χαρακτήρες. Μπορείτε να το κάνετε αυτό μέσα από τις ρυθμίσεις ή το αρχείο ρυθμίσεων",
|
||||
"StopSelecting": "Διακοπή Επιλογής",
|
||||
"OnHealthRestored": "Στην Αποκατάσταση Υγείας",
|
||||
@@ -529,5 +529,14 @@
|
||||
"BuiltIn": "Ενσωματωμένο",
|
||||
"PublishedDate": "Ημερομηνία δημοσίευσης",
|
||||
"Redirected": "Διευθύνω πάλιν",
|
||||
"AllSearchResultsHiddenByFilter": "Όλα τα αποτελέσματα αποκρύπτονται από το εφαρμοσμένο φίλτρο"
|
||||
"AllSearchResultsHiddenByFilter": "Όλα τα αποτελέσματα αποκρύπτονται από το εφαρμοσμένο φίλτρο",
|
||||
"Download": "Κατεβάστε",
|
||||
"ErrorRestoringBackup": "Σφάλμα κατά την επαναφορά του αντιγράφου ασφαλείας",
|
||||
"ExternalUpdater": "Το {appName} έχει ρυθμιστεί να χρησιμοποιεί έναν εξωτερικό μηχανισμό ενημέρωσης",
|
||||
"NoEventsFound": "Δεν βρέθηκαν συμβάντα",
|
||||
"RestartReloadNote": "Σημείωση: Το {appName} θα επανεκκινήσει αυτόματα και θα φορτώσει ξανά το περιβάλλον εργασίας χρήστη κατά τη διαδικασία επαναφοράς.",
|
||||
"UpdateAppDirectlyLoadError": "Δεν είναι δυνατή η απευθείας ενημέρωση του {appName},",
|
||||
"DockerUpdater": "ενημερώστε το κοντέινερ για να λάβετε την ενημέρωση",
|
||||
"AptUpdater": "Χρησιμοποιήστε το apt για να εγκαταστήσετε την ενημέρωση",
|
||||
"InstallLatest": "Εγκατάσταση πιο πρόσφατου"
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
"Apps": "Apps",
|
||||
"AppsMinimumSeeders": "Apps Minimum Seeders",
|
||||
"AppsMinimumSeedersHelpText": "Minimum seeders required by the Applications for the indexer to grab, empty is Sync profile's default",
|
||||
"AptUpdater": "Use apt to install the update",
|
||||
"AreYouSureYouWantToDeleteCategory": "Are you sure you want to delete mapped category?",
|
||||
"AreYouSureYouWantToDeleteIndexer": "Are you sure you want to delete '{name}' from {appName}?",
|
||||
"Artist": "Artist",
|
||||
@@ -98,6 +99,7 @@
|
||||
"BackupNow": "Backup Now",
|
||||
"BackupRetentionHelpText": "Automatic backups older than the retention period will be cleaned up automatically",
|
||||
"Backups": "Backups",
|
||||
"BackupsLoadError": "Unable to load backups",
|
||||
"BasicSearch": "Basic Search",
|
||||
"BeforeUpdate": "Before update",
|
||||
"BindAddress": "Bind Address",
|
||||
@@ -184,8 +186,10 @@
|
||||
"DisabledUntil": "Disabled Until",
|
||||
"Discord": "Discord",
|
||||
"Docker": "Docker",
|
||||
"DockerUpdater": "Update the docker container to receive the update",
|
||||
"Donate": "Donate",
|
||||
"Donations": "Donations",
|
||||
"Download": "Download",
|
||||
"DownloadClient": "Download Client",
|
||||
"DownloadClientAriaSettingsDirectoryHelpText": "Optional location to put downloads in, leave blank to use the default Aria2 location",
|
||||
"DownloadClientCategory": "Download Client Category",
|
||||
@@ -269,12 +273,16 @@
|
||||
"Episode": "Episode",
|
||||
"Error": "Error",
|
||||
"ErrorLoadingContents": "Error loading contents",
|
||||
"ErrorRestoringBackup": "Error restoring backup",
|
||||
"EventType": "Event Type",
|
||||
"Events": "Events",
|
||||
"Exception": "Exception",
|
||||
"ExistingTag": "Existing tag",
|
||||
"External": "External",
|
||||
"ExternalUpdater": "{appName} is configured to use an external update mechanism",
|
||||
"Failed": "Failed",
|
||||
"FailedToFetchSettings": "Failed to fetch settings",
|
||||
"FailedToFetchUpdates": "Failed to fetch updates",
|
||||
"FeatureRequests": "Feature Requests",
|
||||
"Filename": "Filename",
|
||||
"Files": "Files",
|
||||
@@ -438,6 +446,11 @@
|
||||
"Info": "Info",
|
||||
"InfoUrl": "Info URL",
|
||||
"InitialFailure": "Initial Failure",
|
||||
"Install": "Install",
|
||||
"InstallLatest": "Install Latest",
|
||||
"InstallMajorVersionUpdate": "Install Update",
|
||||
"InstallMajorVersionUpdateMessage": "This update will install a new major version and may not be compatible with your system. Are you sure you want to install this update?",
|
||||
"InstallMajorVersionUpdateMessageLink": "Please check [{domain}]({url}) for more information.",
|
||||
"InstanceName": "Instance Name",
|
||||
"InstanceNameHelpText": "Instance name in tab and for Syslog app name",
|
||||
"InteractiveSearch": "Interactive Search",
|
||||
@@ -455,11 +468,13 @@
|
||||
"Level": "Level",
|
||||
"Link": "Link",
|
||||
"LogFiles": "Log Files",
|
||||
"LogFilesLocation": "Log files are located in: {location}",
|
||||
"LogLevel": "Log Level",
|
||||
"LogLevelTraceHelpTextWarning": "Trace logging should only be enabled temporarily",
|
||||
"LogSizeLimit": "Log Size Limit",
|
||||
"LogSizeLimitHelpText": "Maximum log file size in MB before archiving. Default is 1MB.",
|
||||
"Logging": "Logging",
|
||||
"Logout": "Logout",
|
||||
"Logs": "Logs",
|
||||
"MIA": "MIA",
|
||||
"MaintenanceRelease": "Maintenance Release: bug fixes and other improvements. See Github Commit History for more details",
|
||||
@@ -496,6 +511,7 @@
|
||||
"NoChange": "No Change",
|
||||
"NoChanges": "No Changes",
|
||||
"NoDownloadClientsFound": "No download clients found",
|
||||
"NoEventsFound": "No events found",
|
||||
"NoHistoryFound": "No history found",
|
||||
"NoIndexerCategories": "No categories found for this indexer",
|
||||
"NoIndexerHistory": "No history found for this indexer",
|
||||
@@ -529,6 +545,7 @@
|
||||
"OnHealthIssueHelpText": "On Health Issue",
|
||||
"OnHealthRestored": "On Health Restored",
|
||||
"OnHealthRestoredHelpText": "On Health Restored",
|
||||
"OnLatestVersion": "The latest version of {appName} is already installed",
|
||||
"Open": "Open",
|
||||
"OpenBrowserOnStart": "Open browser on start",
|
||||
"OpenThisModal": "Open This Modal",
|
||||
@@ -606,6 +623,7 @@
|
||||
"Restart": "Restart",
|
||||
"RestartNow": "Restart Now",
|
||||
"RestartProwlarr": "Restart {appName}",
|
||||
"RestartReloadNote": "Note: {appName} will automatically restart and reload the UI during the restore process.",
|
||||
"RestartRequiredHelpTextWarning": "Requires restart to take effect",
|
||||
"Restore": "Restore",
|
||||
"RestoreBackup": "Restore Backup",
|
||||
@@ -703,7 +721,7 @@
|
||||
"TestAllApps": "Test All Apps",
|
||||
"TestAllClients": "Test All Clients",
|
||||
"TestAllIndexers": "Test All Indexers",
|
||||
"TheLatestVersionIsAlreadyInstalled": "The latest version of {appName} is already installed",
|
||||
"TheLogLevelDefault": "The log level defaults to 'Info' and can be changed in [General Settings](/settings/general)",
|
||||
"Theme": "Theme",
|
||||
"ThemeHelpText": "Change Application UI Theme, 'Auto' Theme will use your OS Theme to set Light or Dark mode. Inspired by {inspiredBy}.",
|
||||
"Time": "Time",
|
||||
@@ -743,7 +761,6 @@
|
||||
"UnableToAddANewIndexerProxyPleaseTryAgain": "Unable to add a new indexer proxy, please try again.",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Unable to add a new notification, please try again.",
|
||||
"UnableToLoadAppProfiles": "Unable to load app profiles",
|
||||
"UnableToLoadBackups": "Unable to load backups",
|
||||
"UnableToLoadDevelopmentSettings": "Unable to load Development settings",
|
||||
"UnableToLoadGeneralSettings": "Unable to load General settings",
|
||||
"UnableToLoadHistory": "Unable to load history",
|
||||
@@ -754,6 +771,7 @@
|
||||
"UnableToLoadUISettings": "Unable to load UI settings",
|
||||
"UnsavedChanges": "Unsaved Changes",
|
||||
"UnselectAll": "Unselect All",
|
||||
"UpdateAppDirectlyLoadError": "Unable to update {appName} directly,",
|
||||
"UpdateAutomaticallyHelpText": "Automatically download and install updates. You will still be able to install from System: Updates",
|
||||
"UpdateAvailableHealthCheckMessage": "New update is available: {version}",
|
||||
"UpdateMechanismHelpText": "Use {appName}'s built-in updater or a script",
|
||||
@@ -761,6 +779,7 @@
|
||||
"UpdateStartupNotWritableHealthCheckMessage": "Cannot install update because startup folder '{startupFolder}' is not writable by the user '{userName}'.",
|
||||
"UpdateStartupTranslocationHealthCheckMessage": "Cannot install update because startup folder '{startupFolder}' is in an App Translocation folder.",
|
||||
"UpdateUiNotWritableHealthCheckMessage": "Cannot install update because UI folder '{uiFolder}' is not writable by the user '{userName}'.",
|
||||
"UpdaterLogFiles": "Updater Log Files",
|
||||
"Updates": "Updates",
|
||||
"Uptime": "Uptime",
|
||||
"Url": "Url",
|
||||
@@ -778,6 +797,7 @@
|
||||
"Website": "Website",
|
||||
"WhatsNew": "What's New?",
|
||||
"Wiki": "Wiki",
|
||||
"WouldYouLikeToRestoreBackup": "Would you like to restore the backup '{name}'?",
|
||||
"XmlRpcPath": "XML RPC Path",
|
||||
"Year": "Year",
|
||||
"Yes": "Yes",
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"Scheduled": "Programado",
|
||||
"SaveChanges": "Guardar cambios",
|
||||
"RestoreBackup": "Restaurar copia de seguridad",
|
||||
"ReleaseBranchCheckOfficialBranchMessage": "Las versión {0} no es una versión válida de {appName}, no recibirás actualizaciones",
|
||||
"ReleaseBranchCheckOfficialBranchMessage": "La rama {0} no es una rama de lanzamiento válida de {appName}, no recibirás actualizaciones",
|
||||
"Refresh": "Actualizar",
|
||||
"Queue": "Cola",
|
||||
"ProxyResolveIpHealthCheckMessage": "No se pudo resolver la dirección IP del Host Proxy configurado {proxyHostName}",
|
||||
@@ -73,7 +73,7 @@
|
||||
"LastWriteTime": "Última Fecha de Escritura",
|
||||
"IndexerStatusUnavailableHealthCheckMessage": "Indexadores no disponibles debido a errores: {indexerNames}",
|
||||
"Indexer": "Indexador",
|
||||
"Grabbed": "Añadido",
|
||||
"Grabbed": "Capturado",
|
||||
"GeneralSettingsSummary": "Puerto, SSL, nombre de usuario/contraseña , proxy, analíticas, y actualizaciones",
|
||||
"Filename": "Nombre de archivo",
|
||||
"Failed": "Fallido",
|
||||
@@ -99,7 +99,7 @@
|
||||
"Peers": "Pares",
|
||||
"PageSize": "Tamaño de Página",
|
||||
"Ok": "Ok",
|
||||
"OAuthPopupMessage": "Pop-ups bloqueados por su navegador",
|
||||
"OAuthPopupMessage": "Los elementos emergentes están siendo bloqueados por tu navegador",
|
||||
"Name": "Nombre",
|
||||
"Message": "Mensaje",
|
||||
"Level": "Nivel",
|
||||
@@ -135,7 +135,7 @@
|
||||
"DownloadClientSettings": "Opciones del cliente de descarga",
|
||||
"Docker": "Docker",
|
||||
"DeleteTag": "Eliminar Etiqueta",
|
||||
"DeleteNotification": "Borrar Notificacion",
|
||||
"DeleteNotification": "Eliminar Notificación",
|
||||
"DeleteDownloadClient": "Borrar cliente de descarga",
|
||||
"DeleteBackup": "Eliminar copia de seguridad",
|
||||
"DatabaseMigration": "Migración de la base de datos",
|
||||
@@ -143,7 +143,7 @@
|
||||
"ClientPriority": "Prioridad del Cliente",
|
||||
"ChangeHasNotBeenSavedYet": "El cambio aún no se ha guardado",
|
||||
"CertificateValidationHelpText": "Cambiar la rigidez de la validación de la certificación HTTPS",
|
||||
"CertificateValidation": "Validacion de certificado",
|
||||
"CertificateValidation": "Validación de certificado",
|
||||
"BypassProxyForLocalAddresses": "Omitir Proxy para Direcciones Locales",
|
||||
"Branch": "Rama",
|
||||
"BindAddressHelpText": "Dirección IP4 válida, localhost o '*' para todas las interfaces",
|
||||
@@ -171,7 +171,7 @@
|
||||
"UpdateAutomaticallyHelpText": "Descargar e instalar actualizaciones automáticamente. Todavía puedes instalar desde Sistema: Actualizaciones",
|
||||
"UnableToLoadTags": "No se pueden cargar las Etiquetas",
|
||||
"UnableToLoadNotifications": "No se pueden cargar las Notificaciones",
|
||||
"DownloadClientsLoadError": "No se puden cargar los gestores de descargas",
|
||||
"DownloadClientsLoadError": "No se pudieron cargar los clientes de descargas",
|
||||
"UISettings": "Ajustes del UI",
|
||||
"Torrents": "Torrents",
|
||||
"TestAllClients": "Probar todos los clientes",
|
||||
@@ -212,7 +212,7 @@
|
||||
"Mechanism": "Mecanismo",
|
||||
"Logs": "Registros",
|
||||
"LogLevel": "Nivel de Registro",
|
||||
"LaunchBrowserHelpText": " Abrir un navegador web e ir a la página de inicio de {appName} al arrancar la app.",
|
||||
"LaunchBrowserHelpText": " Abre un navegador web y navega a la página de inicio de {appName} al iniciarse la aplicación.",
|
||||
"Interval": "Intervalo",
|
||||
"IndexerFlags": "Indicadores del indexador",
|
||||
"IncludeHealthWarningsHelpText": "Incluir Alertas de Salud",
|
||||
@@ -236,19 +236,19 @@
|
||||
"ExistingTag": "Etiquetas existentes",
|
||||
"EnableInteractiveSearchHelpText": "Se usará cuando se utilice la búsqueda interactiva",
|
||||
"EnableAutomaticSearchHelpText": "Será usado cuando las búsquedas automáticas sean realizadas por la interfaz de usuario o por {appName}",
|
||||
"DeleteTagMessageText": "¿Está seguro de querer eliminar la etiqueta '{label}'?",
|
||||
"DeleteNotificationMessageText": "¿Seguro que quieres eliminar la notificación '{name}'?",
|
||||
"DeleteBackupMessageText": "Seguro que quieres eliminar la copia de seguridad '{name}'?",
|
||||
"DeleteDownloadClientMessageText": "Seguro que quieres eliminar el gestor de descargas '{name}'?",
|
||||
"CancelPendingTask": "Estas seguro de que deseas cancelar esta tarea pendiente?",
|
||||
"BranchUpdateMechanism": "La rama se uso por un mecanisco de actualizacion externo",
|
||||
"DeleteTagMessageText": "¿Estás seguro que quieres eliminar la etiqueta '{label}'?",
|
||||
"DeleteNotificationMessageText": "¿Estás seguro que quieres eliminar la notificación '{name}'?",
|
||||
"DeleteBackupMessageText": "¿Estás seguro que quieres eliminar la copia de seguridad '{name}'?",
|
||||
"DeleteDownloadClientMessageText": "¿Estás seguro que quieres eliminar el cliente de descarga '{name}'?",
|
||||
"CancelPendingTask": "¿Estás seguro que quieres cancelar esta tarea pendiente?",
|
||||
"BranchUpdateMechanism": "Rama usada por un mecanismo de actualización externo",
|
||||
"BranchUpdate": "Rama a usar para actualizar {appName}",
|
||||
"BeforeUpdate": "Antes de actualizar",
|
||||
"AddingTag": "Añadir etiqueta",
|
||||
"UnableToLoadUISettings": "No se han podido cargar los ajustes de UI",
|
||||
"UnableToLoadHistory": "No se ha podido cargar la historia",
|
||||
"UnableToLoadGeneralSettings": "No se han podido cargar los ajustes Generales",
|
||||
"UnableToLoadBackups": "No se pudo cargar las copias de seguridad",
|
||||
"BackupsLoadError": "No se pudo cargar las copias de seguridad",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "No se ha podido añadir una nueva notificación, prueba otra vez.",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "No se pudo añadir un nuevo indexador, por favor inténtalo de nuevo.",
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "No se ha podido añadir un nuevo gestor de descargas, prueba otra vez.",
|
||||
@@ -261,7 +261,7 @@
|
||||
"NoTagsHaveBeenAddedYet": "Ninguna etiqueta ha sido añadida aún",
|
||||
"NoLogFiles": "No hay archivos de registro",
|
||||
"NoBackupsAreAvailable": "No hay copias de seguridad disponibles",
|
||||
"MaintenanceRelease": "Lanzamiento de mantenimiento: Corrección de errores y otras mejoras. Ver historial de commits de Github para mas detalle",
|
||||
"MaintenanceRelease": "Lanzamiento de mantenimiento: Corrección de errores y otras mejoras. Ver el historial de commits de Github para más detalles",
|
||||
"ForMoreInformationOnTheIndividualDownloadClients": "Para más información individual de los gestores de descarga, haz clic en lls botones de información.",
|
||||
"FilterPlaceHolder": "Buscar Indexadores",
|
||||
"Exception": "Excepción",
|
||||
@@ -280,8 +280,8 @@
|
||||
"FocusSearchBox": "Enfocar Campo de Búsqueda",
|
||||
"SaveSettings": "Guardar ajustes",
|
||||
"OpenThisModal": "Abrir esta Ventana Modal",
|
||||
"MovieIndexScrollTop": "Indice de Películas: Desplazar hacia arriba",
|
||||
"MovieIndexScrollBottom": "Indice de Películas: Desplazar hacia abajo",
|
||||
"MovieIndexScrollTop": "Índice de Películas: Desplazar hacia arriba",
|
||||
"MovieIndexScrollBottom": "Índice de Películas: Desplazar hacia abajo",
|
||||
"CloseCurrentModal": "Cerrar esta Ventana Modal",
|
||||
"AcceptConfirmationModal": "Aceptar Confirmación de esta Ventana Modal",
|
||||
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Indexadores no disponibles debido a errores durante más de 6 horas: {indexerNames}",
|
||||
@@ -363,7 +363,7 @@
|
||||
"Started": "Iniciado",
|
||||
"Remove": "Eliminar",
|
||||
"Replace": "Reemplazar",
|
||||
"TheLatestVersionIsAlreadyInstalled": "La última versión de {appName} ya está instalada",
|
||||
"OnLatestVersion": "La última versión de {appName} ya está instalada",
|
||||
"Apps": "Aplicaciones",
|
||||
"AddApplication": "Añadir aplicación",
|
||||
"AddCustomFilter": "Añadir Filtro Personalizado",
|
||||
@@ -398,7 +398,7 @@
|
||||
"EditSelectedDownloadClients": "Editar Clientes de Descarga Seleccionados",
|
||||
"EditSelectedIndexers": "Editar Indexadores Seleccionados",
|
||||
"Implementation": "Implementación",
|
||||
"ManageDownloadClients": "Gestionar Clientes de Descarga",
|
||||
"ManageDownloadClients": "Administrar Clientes de Descarga",
|
||||
"ApiKeyValidationHealthCheckMessage": "Actualice su clave de API para que tenga al menos {length} carácteres. Puede hacerlo en los ajustes o en el archivo de configuración",
|
||||
"IndexerDownloadClientHealthCheckMessage": "Indexadores con clientes de descarga inválidos: {indexerNames}.",
|
||||
"Episode": "Episodio",
|
||||
@@ -425,7 +425,7 @@
|
||||
"ResetAPIKeyMessageText": "¿Estás seguro que quieres restablecer tu clave API?",
|
||||
"EditIndexerProxyImplementation": "Editar proxy de indexador - {implementationName}",
|
||||
"AppUpdated": "{appName} Actualizado",
|
||||
"AppUpdatedVersion": "{appName} ha sido actualizado a la versión `{version}`, para obtener los cambios más recientes, necesitará recargar {appName}",
|
||||
"AppUpdatedVersion": "{appName} ha sido actualizado a la versión `{version}`, para obtener los cambios más recientes tendrás que recargar {appName}",
|
||||
"AddApplicationImplementation": "Agregar aplicación - {implementationName}",
|
||||
"AddConnectionImplementation": "Añadir Conexión - {implementationName}",
|
||||
"AddIndexerImplementation": "Agregar Indexador - {implementationName}",
|
||||
@@ -493,9 +493,9 @@
|
||||
"EditCategory": "Editar categoría",
|
||||
"EditSyncProfile": "Editar perfil de sincronización",
|
||||
"EnableIndexer": "Habilitar indexador",
|
||||
"InvalidUILanguage": "Su interfaz de usuario está configurada en un idioma no válido, corríjalo y guarde la configuración",
|
||||
"InvalidUILanguage": "Tu interfaz de usuario está configurada en un idioma inválido, corrígelo y guarda la configuración",
|
||||
"DownloadClientQbittorrentSettingsContentLayout": "Diseño del contenido",
|
||||
"DownloadClientQbittorrentSettingsContentLayoutHelpText": "Si usar el diseño de contenido configurado de qBittorrent, el diseño original del torrent o siempre crear una subcarpeta (qBittorrent 4.3.2+)",
|
||||
"DownloadClientQbittorrentSettingsContentLayoutHelpText": "Si usa el diseño de contenido configurado de qBittorrent, el diseño original del torrent o siempre crea una subcarpeta (qBittorrent 4.3.2+)",
|
||||
"EnableRssHelpText": "Habilitar canal RSS para el Indexador",
|
||||
"days": "días",
|
||||
"ElapsedTime": "Tiempo transcurrido",
|
||||
@@ -517,7 +517,7 @@
|
||||
"IndexerTagsHelpTextWarning": "Las etiquetas deben utilizarse con precaución, ya que pueden tener efectos no deseados. Un indexador con una etiqueta solo se sincronizará con aplicaciones que tengan la misma etiqueta.",
|
||||
"TVSearchTypes": "Tipos de búsqueda de TV",
|
||||
"DownloadClientAriaSettingsDirectoryHelpText": "Ubicación opcional en la que poner las descargas, dejar en blanco para usar la ubicación de Aria2 predeterminada",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "Los indexadores no tienen definición y no funcionarán: {0}. Por favor elimínelos y (o) vuelva a añadirlos a {appName}.",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "Los indexadores no tienen definición y no funcionarán: {indexerNames}. Por favor elimínalos y (o) vuelve a añadirlos a {appName}.",
|
||||
"IndexerProxy": "Proxy del Indexador",
|
||||
"IndexerObsoleteCheckMessage": "Los indexadores están obsoletos o se han actualizado: {0}. Por favor elimínelos y (o) vuelva a añadirlos a {appName}",
|
||||
"IncludeManualGrabsHelpText": "Incluir las Capturas Manuales realizadas en {appName}",
|
||||
@@ -537,7 +537,7 @@
|
||||
"IndexerTagsHelpText": "Utilice etiquetas para especificar los Proxies del Indexador o las aplicaciones con las que se sincroniza el indexador.",
|
||||
"MassEditor": "Editor Masivo",
|
||||
"ApplicationsLoadError": "No se puede cargar la lista de aplicaciones",
|
||||
"ManageClients": "Gestionar Clientes",
|
||||
"ManageClients": "Administrar Clientes",
|
||||
"ManageApplications": "Gestionar Aplicaciones",
|
||||
"IndexerId": "ID del Indexador",
|
||||
"IndexerInfo": "Información del Indexador",
|
||||
@@ -609,10 +609,10 @@
|
||||
"Url": "Url",
|
||||
"VipExpiration": "Expiración VIP",
|
||||
"TotalIndexerSuccessfulGrabs": "Capturas con Éxito Totales por Indexador",
|
||||
"NotificationsEmailSettingsUseEncryptionHelpText": "Si prefiere utilizar el cifrado si está configurado en el servidor, utilizar siempre el cifrado mediante SSL (sólo puerto 465) o StartTLS (cualquier otro puerto) o no utilizar nunca el cifrado",
|
||||
"NotificationsEmailSettingsUseEncryptionHelpText": "Si prefiere utilizar el cifrado si está configurado en el servidor, utilizar siempre el cifrado mediante SSL (sólo puerto 465) o StartTLS (cualquier otro puerto), o no utilizar nunca el cifrado",
|
||||
"IndexerHDBitsSettingsPasskeyHelpText": "Clave de acceso desde los Detalles de Usuario",
|
||||
"IndexerSettingsPasskey": "Clave de Acceso",
|
||||
"BlackholeFolderHelpText": "La carpeta en donde {appName} se almacenaran los {extension} file",
|
||||
"BlackholeFolderHelpText": "La carpeta donde {appName} almacenará los archivos {extension}",
|
||||
"CustomFilter": "Filtro personalizado",
|
||||
"LabelIsRequired": "Se requiere etiqueta",
|
||||
"TorrentBlackholeSaveMagnetFiles": "Guardar archivos magnet",
|
||||
@@ -771,7 +771,7 @@
|
||||
"AverageGrabs": "Promedio de capturas",
|
||||
"AllSearchResultsHiddenByFilter": "Todos los resultados están ocultos por el filtro aplicado.",
|
||||
"PackageVersionInfo": "{packageVersion} por {packageAuthor}",
|
||||
"HealthMessagesInfoBox": "Puede encontrar más información sobre la causa de estos mensajes de comprobación de salud haciendo clic en el enlace wiki (icono de libro) al final de la fila, o comprobando sus [logs]({link}). Si tienes dificultades para interpretar estos mensajes, puedes ponerte en contacto con nuestro servicio de asistencia en los enlaces que aparecen a continuación.",
|
||||
"HealthMessagesInfoBox": "Puedes encontrar más información sobre la causa de estos mensajes de comprobación de salud haciendo clic en el enlace wiki (icono de libro) al final de la fila, o comprobando tus [registros]({link}). Si tienes dificultades para interpretar estos mensajes, puedes ponerte en contacto con nuestro soporte en los enlaces que aparecen abajo.",
|
||||
"LogSizeLimit": "Límite de tamaño de registro",
|
||||
"LogSizeLimitHelpText": "Máximo tamaño de archivo de registro en MB antes de archivarlo. Predeterminado es 1MB.",
|
||||
"PreferMagnetUrl": "Preferir URL magnet",
|
||||
@@ -784,5 +784,25 @@
|
||||
"IndexerAvistazSettingsUsernameHelpText": "Nombre de usuario del sitio",
|
||||
"IndexerAvistazSettingsUsernameHelpTextWarning": "Solo los miembros de rango y superiores pueden usar la API en este indexador.",
|
||||
"IndexerAvistazSettingsPasswordHelpText": "Contraseña del sitio",
|
||||
"IndexerAvistazSettingsPidHelpText": "PID de la página de Mi cuenta o Mi perfil"
|
||||
"IndexerAvistazSettingsPidHelpText": "PID de la página de Mi cuenta o Mi perfil",
|
||||
"LogFilesLocation": "Los archivos de registro se encuentran en: {location}",
|
||||
"DockerUpdater": "Actualiza el contenedor docker para recibir la actualización",
|
||||
"Download": "Descargar",
|
||||
"ErrorRestoringBackup": "Error restaurando la copia de seguridad",
|
||||
"ExternalUpdater": "{appName} está configurado para usar un mecanismo de actualización externo",
|
||||
"FailedToFetchUpdates": "Fallo al buscar las actualizaciones",
|
||||
"Logout": "Cerrar Sesión",
|
||||
"NoEventsFound": "Ningún evento encontrado",
|
||||
"RestartReloadNote": "Nota: {appName} se reiniciará automáticamente y recargará la interfaz durante el proceso de restauración.",
|
||||
"TheLogLevelDefault": "El nivel de registro por defecto es 'Info' y puede ser cambiado en [Opciones generales](opciones/general)",
|
||||
"UpdateAppDirectlyLoadError": "No se pudo actualizar {appName} directamente,",
|
||||
"UpdaterLogFiles": "Actualizador de archivos de registro",
|
||||
"WouldYouLikeToRestoreBackup": "Te gustaria restaurar la copia de seguridad '{name}'?",
|
||||
"AptUpdater": "Usa apt para instalar la actualización",
|
||||
"Install": "Instalar",
|
||||
"InstallLatest": "Instala el último",
|
||||
"InstallMajorVersionUpdateMessage": "Esta actualización instalará una nueva versión principal y podría no ser compatible con tu sistema. ¿Estás seguro que quieres instalar esta actualización?",
|
||||
"InstallMajorVersionUpdate": "Instalar actualización",
|
||||
"InstallMajorVersionUpdateMessageLink": "Por favor revisa [{domain}]({url}) para más información.",
|
||||
"FailedToFetchSettings": "Error al recuperar la configuración"
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
"UnableToAddANewApplicationPleaseTryAgain": "Uuden sovelluksen lisäys epäonnistui. Yritä uudelleen.",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "Uuden tietolähteen lisäys epäonnistui. Yritä uudelleen.",
|
||||
"UnableToAddANewIndexerProxyPleaseTryAgain": "Uuden tiedonhaun välityspalvelimen lisäys epäonnistui. Yritä uudelleen.",
|
||||
"UnableToLoadBackups": "Varmuuskopioiden lataus epäonnistui",
|
||||
"BackupsLoadError": "Varmuuskopioiden lataus epäonnistui",
|
||||
"DownloadClientsLoadError": "Lataustyökalujen lataus ei onistu",
|
||||
"UnableToLoadGeneralSettings": "Virhe ladattaessa yleisiä asetuksia",
|
||||
"UpdateAutomaticallyHelpText": "Lataa ja asenna päivitykset automaattisesti. Voit myös edelleen suorittaa asennuksen järjestelmäasetusten päivitykset-osiosta.",
|
||||
@@ -405,7 +405,7 @@
|
||||
"ApplicationsLoadError": "Sovelluslistausta ei voitu ladata",
|
||||
"Url": "URL",
|
||||
"Website": "Verkkosivusto",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "Tietolähteillä ei ole määritystä, eivätkä ne toimi: {0}. Poista ja/tai lisää {appName}iin uudelleen",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "Tietolähteillä ei ole määritystä, eivätkä ne toimi: {indexerNames}. Poista ja/tai lisää {appName}iin uudelleen",
|
||||
"Private": "Yksityinen",
|
||||
"QueryResults": "Kyselyn tulokset",
|
||||
"Application": "Sovellus",
|
||||
@@ -455,7 +455,7 @@
|
||||
"AuthenticationRequired": "Vaadi tunnistautuminen",
|
||||
"Remove": "Poista",
|
||||
"Replace": "Korvaa",
|
||||
"TheLatestVersionIsAlreadyInstalled": "{appName}in uusin versio on jo asennettu",
|
||||
"OnLatestVersion": "{appName}in uusin versio on jo asennettu",
|
||||
"ApplicationURL": "Sovelluksen URL",
|
||||
"ApplicationUrlHelpText": "Tämän sovelluksen ulkoinen URL-osoite, johon sisältyy http(s)://, portti ja URL-perusta.",
|
||||
"Track": "Valvo",
|
||||
@@ -699,5 +699,20 @@
|
||||
"Redirected": "Uudelleenohjaus",
|
||||
"AllSearchResultsHiddenByFilter": "Aktiivinen suodatin piilottaa kaikki tulokset.",
|
||||
"HealthMessagesInfoBox": "Saat lisätietoja näiden vakausviestien syistä painamalla rivin lopussa olevaa wikilinkkiä (kirjakuvake) tai tarkastelemalla [lokitietoja]({link}). Mikäli kohtaat ongelmia näiden viestien tulkinnassa, tavoitat tukemme alla olevilla linkkeillä.",
|
||||
"PackageVersionInfo": "{packageVersion} julkaisijalta {packageAuthor}"
|
||||
"PackageVersionInfo": "{packageVersion} julkaisijalta {packageAuthor}",
|
||||
"ErrorRestoringBackup": "Virhe palautettaessa varmuuskopiota",
|
||||
"ExternalUpdater": "{appName} on määritetty käyttämään ulkoista päivitysratkaisua.",
|
||||
"FailedToFetchUpdates": "Päivitysten nouto epäonnistui",
|
||||
"AptUpdater": "Asenna päivitys APT-työkalun avulla",
|
||||
"DockerUpdater": "Hanki päivitys päivittämällä Docker-säiliö",
|
||||
"Download": "Lataa",
|
||||
"LogFilesLocation": "Lokitiedostojen tallennussijainti: {location}",
|
||||
"Logout": "Kirjaudu ulos",
|
||||
"NoEventsFound": "Tapahtumia ei löytynyt",
|
||||
"RestartReloadNote": "Huomioi: {appName} käynnistyy palautusprosessin aikana automaattisesti uudelleen.",
|
||||
"TheLogLevelDefault": "Lokikirjauksen oletusarvoinen laajuus on \"Informatiivinen\". Laajuutta voidaan muuttaa [Yleisistä asetuksista](/settings/general).",
|
||||
"UpdateAppDirectlyLoadError": "{appName}ia ei voida päivittää suoraan,",
|
||||
"UpdaterLogFiles": "Päivittäjän lokitiedostot",
|
||||
"WouldYouLikeToRestoreBackup": "Haluatko palauttaa varmuuskopion \"{name}\"?",
|
||||
"InstallLatest": "Asenna uusin"
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
"UnableToLoadHistory": "Impossible de charger l'historique",
|
||||
"UnableToLoadGeneralSettings": "Impossible de charger les paramètres généraux",
|
||||
"DownloadClientsLoadError": "Impossible de charger les clients de téléchargement",
|
||||
"UnableToLoadBackups": "Impossible de charger les sauvegardes",
|
||||
"BackupsLoadError": "Impossible de charger les sauvegardes",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Impossible d'ajouter une nouvelle notification, veuillez réessayer.",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "Impossible d'ajouter un nouvel indexeur, veuillez réessayer.",
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "Impossible d'ajouter un nouveau client de téléchargement, veuillez réessayer.",
|
||||
@@ -458,7 +458,7 @@
|
||||
"AuthenticationRequiredWarning": "Pour empêcher l'accès à distance sans authentification, {appName} exige désormais que l'authentification soit activée. Vous pouvez éventuellement désactiver l'authentification pour les adresses locales.",
|
||||
"Remove": "Retirer",
|
||||
"Replace": "Remplacer",
|
||||
"TheLatestVersionIsAlreadyInstalled": "La dernière version de {appName} est déjà installée",
|
||||
"OnLatestVersion": "La dernière version de {appName} est déjà installée",
|
||||
"AddCustomFilter": "Ajouter filtre personnalisé",
|
||||
"AddApplication": "Ajouter une application",
|
||||
"IncludeManualGrabsHelpText": "Inclure les saisies manuelles effectuées dans {appName}",
|
||||
@@ -775,5 +775,29 @@
|
||||
"LogSizeLimit": "Limite de taille du journal",
|
||||
"LogSizeLimitHelpText": "Taille maximale du fichier journal en Mo avant archivage. La valeur par défaut est de 1 Mo.",
|
||||
"IndexerAvistazSettingsFreeleechOnlyHelpText": "Rechercher les publications freeleech uniquement",
|
||||
"IndexerAvistazSettingsUsernameHelpText": "Nom d'utilisateur du site"
|
||||
"IndexerAvistazSettingsUsernameHelpText": "Nom d'utilisateur du site",
|
||||
"DockerUpdater": "Mettez à jour le conteneur Docker pour recevoir la mise à jour",
|
||||
"Download": "Téléchargement",
|
||||
"ErrorRestoringBackup": "Erreur lors de la restauration de la sauvegarde",
|
||||
"ExternalUpdater": "{appName} est configuré pour utiliser un mécanisme de mise à jour externe",
|
||||
"FailedToFetchUpdates": "Échec de la récupération des mises à jour",
|
||||
"LogFilesLocation": "Les fichiers journaux sont situés dans : {location}",
|
||||
"Logout": "Se déconnecter",
|
||||
"NoEventsFound": "Aucun événement trouvé",
|
||||
"RestartReloadNote": "Remarque : {appName} redémarrera et rechargera automatiquement l'interface utilisateur pendant le processus de restauration.",
|
||||
"TheLogLevelDefault": "Le niveau de journalisation est par défaut à « Information » et peut être modifié dans les [paramètres généraux](/settings/general)",
|
||||
"UpdateAppDirectlyLoadError": "Impossible de mettre à jour directement {appName},",
|
||||
"UpdaterLogFiles": "Journaux du programme de mise à jour",
|
||||
"WouldYouLikeToRestoreBackup": "Souhaitez-vous restaurer la sauvegarde « {name} » ?",
|
||||
"AptUpdater": "Utiliser apt pour installer la mise à jour",
|
||||
"Install": "Installer",
|
||||
"InstallLatest": "Installer la dernière",
|
||||
"InstallMajorVersionUpdateMessageLink": "Veuillez consulter [{domain}]({url}) pour plus d'informations.",
|
||||
"InstallMajorVersionUpdate": "Installer la mise à jour",
|
||||
"InstallMajorVersionUpdateMessage": "Cette mise à jour installera une nouvelle version majeure et pourrait ne pas être compatible avec votre système. Êtes-vous sûr de vouloir installer cette mise à jour ?",
|
||||
"FailedToFetchSettings": "Échec de la récupération des paramètres",
|
||||
"IndexerSettingsPreferMagnetUrlHelpText": "Si activé, cet indexeur privilégiera si possible l'usage de liens de type magnet aux liens torrent",
|
||||
"PreferMagnetUrl": "Privilégier les liens de type magnet",
|
||||
"IndexerAvistazSettingsPidHelpText": "PID de la page Mon compte ou Mon profil",
|
||||
"IndexerAvistazSettingsPasswordHelpText": "Mot de passe du site"
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
"UILanguageHelpTextWarning": "חובה לטעון דפדפן",
|
||||
"UISettings": "הגדרות ממשק המשתמש",
|
||||
"UnableToAddANewAppProfilePleaseTryAgain": "לא ניתן להוסיף פרופיל איכות חדש, נסה שוב.",
|
||||
"UnableToLoadBackups": "לא ניתן לטעון גיבויים",
|
||||
"BackupsLoadError": "לא ניתן לטעון גיבויים",
|
||||
"UnableToLoadTags": "לא ניתן לטעון תגים",
|
||||
"UnableToLoadUISettings": "לא ניתן לטעון הגדרות ממשק משתמש",
|
||||
"UnsavedChanges": "שינויים שלא נשמרו",
|
||||
@@ -371,7 +371,7 @@
|
||||
"EditSyncProfile": "הוספת פרופיל סינכרון",
|
||||
"Notifications": "התראות",
|
||||
"Notification": "התראות",
|
||||
"TheLatestVersionIsAlreadyInstalled": "הגרסה האחרונה של {appName} כבר מותקנת",
|
||||
"OnLatestVersion": "הגרסה האחרונה של {appName} כבר מותקנת",
|
||||
"Remove": "לְהַסִיר",
|
||||
"Replace": "החלף",
|
||||
"AddApplication": "הוספת אפליקציה",
|
||||
@@ -418,5 +418,14 @@
|
||||
"AddCategory": "הוסף קטגוריה",
|
||||
"ActiveApps": "אפליקציות פעילות",
|
||||
"ActiveIndexers": "אינדקסרים פעילים",
|
||||
"AllSearchResultsHiddenByFilter": "כל התוצאות מוסתרות על ידי המסנן שהוחל"
|
||||
"AllSearchResultsHiddenByFilter": "כל התוצאות מוסתרות על ידי המסנן שהוחל",
|
||||
"InstallLatest": "התקן את האחרונה",
|
||||
"NoEventsFound": "לא נמצאו אירועים",
|
||||
"DockerUpdater": "עדכן את מיכל העגינה לקבל את העדכון",
|
||||
"Download": "הורד",
|
||||
"ErrorRestoringBackup": "שגיאה בשחזור הגיבוי",
|
||||
"ExternalUpdater": "{appName} מוגדר להשתמש במנגנון עדכון חיצוני",
|
||||
"RestartReloadNote": "הערה: {appName} יופעל מחדש אוטומטית וטען מחדש את ממשק המשתמש במהלך תהליך השחזור.",
|
||||
"UpdateAppDirectlyLoadError": "לא ניתן לעדכן את {appName} ישירות,",
|
||||
"AptUpdater": "השתמש ב- apt כדי להתקין את העדכון"
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "नया डाउनलोड क्लाइंट जोड़ने में असमर्थ, कृपया पुनः प्रयास करें।",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "नया अनुक्रमणिका जोड़ने में असमर्थ, कृपया पुनः प्रयास करें।",
|
||||
"UnableToAddANewIndexerProxyPleaseTryAgain": "नया अनुक्रमणिका जोड़ने में असमर्थ, कृपया पुनः प्रयास करें।",
|
||||
"UnableToLoadBackups": "बैकअप लोड करने में असमर्थ",
|
||||
"BackupsLoadError": "बैकअप लोड करने में असमर्थ",
|
||||
"NoTagsHaveBeenAddedYet": "अभी तक कोई टैग नहीं जोड़े गए हैं",
|
||||
"Reddit": "reddit",
|
||||
"UpdateMechanismHelpText": "रेडर के बिल्ट इन अपडेटर या स्क्रिप्ट का उपयोग करें",
|
||||
@@ -328,7 +328,7 @@
|
||||
"LastExecution": "अंतिम निष्पादन",
|
||||
"Queued": "कतारबद्ध",
|
||||
"Remove": "हटाना",
|
||||
"TheLatestVersionIsAlreadyInstalled": "रेडर का नवीनतम संस्करण पहले से ही स्थापित है",
|
||||
"OnLatestVersion": "रेडर का नवीनतम संस्करण पहले से ही स्थापित है",
|
||||
"Replace": "बदलने के",
|
||||
"More": "अधिक",
|
||||
"DeleteSelectedDownloadClients": "डाउनलोड क्लाइंट हटाएं",
|
||||
@@ -360,5 +360,13 @@
|
||||
"BuiltIn": "में निर्मित",
|
||||
"Script": "लिपि",
|
||||
"PublishedDate": "प्रकाशित तिथि",
|
||||
"AllSearchResultsHiddenByFilter": "सभी परिणाम लागू फ़िल्टर द्वारा छिपे हुए हैं"
|
||||
"AllSearchResultsHiddenByFilter": "सभी परिणाम लागू फ़िल्टर द्वारा छिपे हुए हैं",
|
||||
"AptUpdater": "अद्यतन स्थापित करने के लिए उपयुक्त का उपयोग करें",
|
||||
"DockerUpdater": "अपडेट प्राप्त करने के लिए docker कंटेनर को अपडेट करें",
|
||||
"Download": "डाउनलोड",
|
||||
"ErrorRestoringBackup": "बैकअप बहाल करने में त्रुटि",
|
||||
"NoEventsFound": "कोई घटना नहीं मिली",
|
||||
"RestartReloadNote": "नोट: रैडियर स्वचालित रूप से पुनः आरंभ करेगा और पुनर्स्थापना प्रक्रिया के दौरान UI को फिर से लोड करेगा।",
|
||||
"UpdateAppDirectlyLoadError": "सीधे {appName} अद्यतन करने में असमर्थ,",
|
||||
"InstallLatest": "नवीनतम स्थापित करें"
|
||||
}
|
||||
|
||||
@@ -208,5 +208,8 @@
|
||||
"UnableToAddANewAppProfilePleaseTryAgain": "Neuspješno dodavanje novog profila kvalitete, molimo pokušaj ponovno.",
|
||||
"EditIndexerImplementation": "Dodaj Indexer - {implementationName}",
|
||||
"AddIndexerProxyImplementation": "Dodaj Indexer - {implementationName}",
|
||||
"UnableToAddANewApplicationPleaseTryAgain": "Neuspješno dodavanje nove obavijesti, molimo pokušaj ponovno."
|
||||
"UnableToAddANewApplicationPleaseTryAgain": "Neuspješno dodavanje nove obavijesti, molimo pokušaj ponovno.",
|
||||
"EditApplicationImplementation": "Dodaj Vezu - {implementationName}",
|
||||
"AptUpdater": "Koristi apt kako bi instalirao ažuriranje",
|
||||
"EditIndexerProxyImplementation": "Dodaj Indexer - {implementationName}"
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@
|
||||
"UnableToLoadHistory": "Nem sikerült betölteni az előzményeket",
|
||||
"UnableToLoadGeneralSettings": "Nem sikerült betölteni az általános beállításokat",
|
||||
"DownloadClientsLoadError": "Nem sikerült betölteni a letöltőkliens(eke)t",
|
||||
"UnableToLoadBackups": "Biztonsági mentés(ek) betöltése sikertelen",
|
||||
"BackupsLoadError": "Biztonsági mentés(ek) betöltése sikertelen",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Nem lehet új értesítést hozzáadni, próbálkozz újra.",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "Nem lehet új indexert hozzáadni, próbálkozz újra.",
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "Nem lehet új letöltőklienst hozzáadni, próbálkozz újra.",
|
||||
@@ -393,7 +393,7 @@
|
||||
"HistoryCleanupDaysHelpTextWarning": "A kiválasztott napszámnál régebbi előzmények automatikusan törlődnek",
|
||||
"IndexerAlreadySetup": "Az indexelő legalább egy példánya már be van állítva",
|
||||
"IndexerInfo": "Indexer információ",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "Az indexereknek nincs definíciójuk, és nem működnek: {0}. Kérjük, távolítsa el és (vagy) adja hozzá újra a {appName}hoz",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "Az indexereknek nincs definíciójuk, és nem működnek: {indexerNames}. Kérjük, távolítsa el és (vagy) adja hozzá újra a {appName}hoz",
|
||||
"MassEditor": "Tömeges szerkesztő",
|
||||
"OnApplicationUpdate": "Alkalmazásfrissítésről",
|
||||
"OnApplicationUpdateHelpText": "Alkalmazásfrissítésről",
|
||||
@@ -456,7 +456,7 @@
|
||||
"AuthenticationRequired": "Azonosítás szükséges",
|
||||
"AuthenticationRequiredHelpText": "Módosítsa, hogy mely kérésekhez van szükség hitelesítésre. Ne változtasson, hacsak nem érti a kockázatokat.",
|
||||
"AuthenticationRequiredWarning": "A hitelesítés nélküli távoli hozzáférés megakadályozása érdekében a(z) {appName} alkalmazásnak engedélyeznie kell a hitelesítést. Opcionálisan letilthatja a helyi címekről történő hitelesítést.",
|
||||
"TheLatestVersionIsAlreadyInstalled": "A {appName} legújabb verziója már telepítva van",
|
||||
"OnLatestVersion": "A {appName} legújabb verziója már telepítva van",
|
||||
"Remove": "Eltávolítás",
|
||||
"Replace": "Kicserél",
|
||||
"ApplicationURL": "Alkalmazás URL",
|
||||
@@ -582,5 +582,18 @@
|
||||
"PublishedDate": "Közzététel dátuma",
|
||||
"Redirected": "Átirányítás",
|
||||
"AllSearchResultsHiddenByFilter": "Az alkalmazott szűrők miatt, az összes keresési eredmény rejtve marad",
|
||||
"HealthMessagesInfoBox": "Az állapotfelmérés okáról további információkat találhat, ha a sor végén található wikilinkre (könyv ikonra) kattint, vagy megnézi [logs] ({link}). Ha nehézségei vannak ezen üzenetek értelmezése során, forduljon ügyfélszolgálatunkhoz az alábbi linkeken."
|
||||
"HealthMessagesInfoBox": "Az állapotfelmérés okáról további információkat találhat, ha a sor végén található wikilinkre (könyv ikonra) kattint, vagy megnézi [logs] ({link}). Ha nehézségei vannak ezen üzenetek értelmezése során, forduljon ügyfélszolgálatunkhoz az alábbi linkeken.",
|
||||
"AptUpdater": "A frissítés telepítéséhez használja az apt-t",
|
||||
"DockerUpdater": "Frissítse a docker-tárolót a frissítés fogadásához",
|
||||
"Download": "Letöltés",
|
||||
"ErrorRestoringBackup": "Hiba a biztonsági mentés visszaállításakor",
|
||||
"ExternalUpdater": "A {appName} egy külső frissítési mechanizmus használatára van konfigurálva",
|
||||
"FailedToFetchUpdates": "Nem sikerült lekérni a frissítéseket",
|
||||
"LogFilesLocation": "A naplófájlok itt találhatók: {location}",
|
||||
"Logout": "Kijelentkezés",
|
||||
"NoEventsFound": "Nem található események",
|
||||
"RestartReloadNote": "Megjegyzés: A {appName} automatikusan újraindítja és újratölti a felületet a visszaállítási folyamatban.",
|
||||
"UpdateAppDirectlyLoadError": "Nem lehetséges közvetlenül frissíteni a {appName}-t",
|
||||
"WouldYouLikeToRestoreBackup": "Szeretné visszaállítani a(z) „{name}” biztonsági másolatot?",
|
||||
"InstallLatest": "Legfrissebb telepítése"
|
||||
}
|
||||
|
||||
@@ -85,5 +85,6 @@
|
||||
"Id": "ID",
|
||||
"IndexerHDBitsSettingsCodecs": "Codec",
|
||||
"ProxyValidationBadRequest": "Gagal menguji proxy. Kode Status: {statusCode}",
|
||||
"AllSearchResultsHiddenByFilter": "Seluruh hasil disembunyikan karena penyaringan yang diterapkan"
|
||||
"AllSearchResultsHiddenByFilter": "Seluruh hasil disembunyikan karena penyaringan yang diterapkan",
|
||||
"AptUpdater": "Gunakan apt untuk memasang pembaruan"
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
"Torrents": "Flæði",
|
||||
"Type": "Tegund",
|
||||
"UnableToAddANewApplicationPleaseTryAgain": "Ekki er hægt að bæta við nýrri tilkynningu. Reyndu aftur.",
|
||||
"UnableToLoadBackups": "Ekki er hægt að hlaða afrit",
|
||||
"BackupsLoadError": "Ekki er hægt að hlaða afrit",
|
||||
"DownloadClientsLoadError": "Ekki er hægt að hlaða niður viðskiptavinum",
|
||||
"UnableToLoadGeneralSettings": "Ekki er hægt að hlaða almennar stillingar",
|
||||
"UnableToLoadHistory": "Ekki er hægt að hlaða sögu",
|
||||
@@ -329,7 +329,7 @@
|
||||
"NextExecution": "Næsta framkvæmd",
|
||||
"Remove": "Fjarlægðu",
|
||||
"Replace": "Skipta um",
|
||||
"TheLatestVersionIsAlreadyInstalled": "Nýjasta útgáfan af {appName} er þegar uppsett",
|
||||
"OnLatestVersion": "Nýjasta útgáfan af {appName} er þegar uppsett",
|
||||
"ApplyTagsHelpTextAdd": "Bæta við: Bættu merkjum við núverandi lista yfir merki",
|
||||
"ApplyTagsHelpTextHowToApplyApplications": "Hvernig á að setja merki á völdu kvikmyndirnar",
|
||||
"ApplyTagsHelpTextHowToApplyIndexers": "Hvernig á að setja merki á völdu kvikmyndirnar",
|
||||
@@ -361,5 +361,14 @@
|
||||
"BuiltIn": "Innbyggð",
|
||||
"Script": "Handrit",
|
||||
"PublishedDate": "Útgáfudagur",
|
||||
"AllSearchResultsHiddenByFilter": "Allar niðurstöður eru faldar af beittu síunni"
|
||||
"AllSearchResultsHiddenByFilter": "Allar niðurstöður eru faldar af beittu síunni",
|
||||
"AptUpdater": "Notaðu apt til að setja uppfærsluna upp",
|
||||
"DockerUpdater": "uppfærðu bryggjugáminn til að fá uppfærsluna",
|
||||
"Download": "Sækja",
|
||||
"ErrorRestoringBackup": "Villa við að endurheimta afrit",
|
||||
"ExternalUpdater": "{appName} er stilltur til að nota ytri uppfærslu",
|
||||
"RestartReloadNote": "Athugið: {appName} mun sjálfkrafa endurræsa og endurhlaða notendaviðmiðið meðan á endurreisnarferlinu stendur.",
|
||||
"UpdateAppDirectlyLoadError": "Ekki er hægt að uppfæra {appName} beint,",
|
||||
"NoEventsFound": "Engir viðburðir fundust",
|
||||
"InstallLatest": "Settu upp nýjustu"
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@
|
||||
"UnableToLoadHistory": "Impossibile caricare la storia",
|
||||
"UnableToLoadGeneralSettings": "Impossibile caricare le impostazioni Generali",
|
||||
"DownloadClientsLoadError": "Impossibile caricare i client di download",
|
||||
"UnableToLoadBackups": "Impossibile caricare i backup",
|
||||
"BackupsLoadError": "Impossibile caricare i backup",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Impossibile aggiungere una nuova notifica, riprova.",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "Impossibile aggiungere un nuovo Indicizzatore, riprova.",
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "Impossibile aggiungere un nuovo client di download, riprova.",
|
||||
@@ -456,7 +456,7 @@
|
||||
"MappedCategories": "Categorie mappate",
|
||||
"Remove": "Rimuovi",
|
||||
"Replace": "Sostituire",
|
||||
"TheLatestVersionIsAlreadyInstalled": "L'ultima versione di {appName} è già installata",
|
||||
"OnLatestVersion": "L'ultima versione di {appName} è già installata",
|
||||
"ApplicationURL": "URL Applicazione",
|
||||
"ApplicationUrlHelpText": "L'URL esterno di questa applicazione, incluso http(s)://, porta e URL base",
|
||||
"Episode": "Episodio",
|
||||
@@ -647,5 +647,16 @@
|
||||
"PublishedDate": "Data Pubblicazione",
|
||||
"Redirected": "Reindirizzamento",
|
||||
"AllSearchResultsHiddenByFilter": "Tutti i risultati sono nascosti dal filtro",
|
||||
"PackageVersionInfo": "{packageVersion} di {packageAuthor}"
|
||||
"PackageVersionInfo": "{packageVersion} di {packageAuthor}",
|
||||
"DockerUpdater": "Aggiorna il container di docker per ricevere l'aggiornamento",
|
||||
"Download": "Scarica",
|
||||
"ErrorRestoringBackup": "Errore durante il ripristino del backup",
|
||||
"ExternalUpdater": "{appName} è configurato per utilizzare un meccanismo di aggiornamento esterno",
|
||||
"LogFilesLocation": "File di Log localizzati in: {location}",
|
||||
"NoEventsFound": "Nessun evento trovato",
|
||||
"RestartReloadNote": "Nota: {appName} si riavvierà automaticamente e ricaricherà l'interfaccia durante il processo di ripristino.",
|
||||
"WouldYouLikeToRestoreBackup": "Vuoi ripristinare il backup '{name}'?",
|
||||
"UpdateAppDirectlyLoadError": "Impossibile aggiornare {appName} direttamente,",
|
||||
"AptUpdater": "Usa apt per installare l'aggiornamento",
|
||||
"InstallLatest": "Installa il più recente"
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "新しいダウンロードクライアントを追加できません。もう一度やり直してください。",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "新しいインデクサーを追加できません。もう一度やり直してください。",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "新しい通知を追加できません。もう一度やり直してください。",
|
||||
"UnableToLoadBackups": "バックアップを読み込めません",
|
||||
"BackupsLoadError": "バックアップを読み込めません",
|
||||
"UnableToLoadHistory": "履歴を読み込めません",
|
||||
"UnableToLoadTags": "タグを読み込めません",
|
||||
"UnableToLoadUISettings": "UI設定を読み込めません",
|
||||
@@ -329,7 +329,7 @@
|
||||
"Queued": "キューに入れられました",
|
||||
"Remove": "削除する",
|
||||
"Replace": "交換",
|
||||
"TheLatestVersionIsAlreadyInstalled": "{appName}の最新バージョンはすでにインストールされています",
|
||||
"OnLatestVersion": "{appName}の最新バージョンはすでにインストールされています",
|
||||
"Track": "痕跡",
|
||||
"DeleteSelectedDownloadClients": "ダウンロードクライアントを削除する",
|
||||
"Genre": "ジャンル",
|
||||
@@ -361,5 +361,14 @@
|
||||
"Script": "脚本",
|
||||
"BuiltIn": "ビルトイン",
|
||||
"PublishedDate": "公開日",
|
||||
"AllSearchResultsHiddenByFilter": "すべての結果は、適用されたフィルターによって非表示になります"
|
||||
"AllSearchResultsHiddenByFilter": "すべての結果は、適用されたフィルターによって非表示になります",
|
||||
"DockerUpdater": "Dockerコンテナを更新して、更新を受信します",
|
||||
"Download": "ダウンロード",
|
||||
"ErrorRestoringBackup": "バックアップの復元中にエラーが発生しました",
|
||||
"ExternalUpdater": "{appName}は、外部更新メカニズムを使用するように構成されています",
|
||||
"NoEventsFound": "イベントが見つかりません",
|
||||
"RestartReloadNote": "注:{appName}は、復元プロセス中にUIを自動的に再起動して再読み込みします。",
|
||||
"UpdateAppDirectlyLoadError": "{appName}を直接更新できません。",
|
||||
"AptUpdater": "aptを使用してアップデートをインストールします",
|
||||
"InstallLatest": "最新のインストール"
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
"UnableToAddANewAppProfilePleaseTryAgain": "새 품질 프로필을 추가 할 수 없습니다. 다시 시도하십시오.",
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "새 다운로드 클라이언트를 추가 할 수 없습니다. 다시 시도하십시오.",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "새 인덱서를 추가 할 수 없습니다. 다시 시도하십시오.",
|
||||
"UnableToLoadBackups": "백업을로드 할 수 없습니다.",
|
||||
"BackupsLoadError": "백업을로드 할 수 없습니다.",
|
||||
"UpdateAutomaticallyHelpText": "업데이트를 자동으로 다운로드하고 설치합니다. 시스템 : 업데이트에서 계속 설치할 수 있습니다.",
|
||||
"RemoveFilter": "필터 제거",
|
||||
"Size": "크기",
|
||||
@@ -328,7 +328,7 @@
|
||||
"LastExecution": "마지막 실행",
|
||||
"Queued": "대기 중",
|
||||
"Replace": "바꾸다",
|
||||
"TheLatestVersionIsAlreadyInstalled": "최신 버전의 Whisparr가 이미 설치되어 있습니다.",
|
||||
"OnLatestVersion": "최신 버전의 Whisparr가 이미 설치되어 있습니다.",
|
||||
"Remove": "없애다",
|
||||
"Genre": "장르",
|
||||
"ApplyTagsHelpTextAdd": "추가 : 기존 태그 목록에 태그를 추가합니다.",
|
||||
@@ -360,5 +360,12 @@
|
||||
"ProxyValidationBadRequest": "프록시를 테스트하지 못했습니다. StatusCode : {statusCode}",
|
||||
"BuiltIn": "내장",
|
||||
"PublishedDate": "발행일",
|
||||
"AllSearchResultsHiddenByFilter": "적용된 필터에 의해 모든 결과가 숨겨집니다."
|
||||
"AllSearchResultsHiddenByFilter": "적용된 필터에 의해 모든 결과가 숨겨집니다.",
|
||||
"DockerUpdater": "Docker 컨테이너를 업데이트하여 업데이트를 받으십시오.",
|
||||
"Download": "다운로드",
|
||||
"ErrorRestoringBackup": "백업 복원 오류",
|
||||
"ExternalUpdater": "{appName}는 외부 업데이트 메커니즘을 사용하도록 구성됩니다.",
|
||||
"RestartReloadNote": "참고 : {appName}는 복원 프로세스 중에 UI를 자동으로 다시 시작하고 다시로드합니다.",
|
||||
"UpdateAppDirectlyLoadError": "{appName}를 직접 업데이트 할 수 없습니다.",
|
||||
"AptUpdater": "apt를 사용하여 업데이트 설치"
|
||||
}
|
||||
|
||||
@@ -156,5 +156,7 @@
|
||||
"EditIndexerProxyImplementation": "Legg til betingelse - {implementationName}",
|
||||
"UnableToAddANewAppProfilePleaseTryAgain": "Ikke mulig å legge til ny betingelse, vennligst prøv igjen",
|
||||
"BuiltIn": "Bygget inn",
|
||||
"AllSearchResultsHiddenByFilter": "Alle resultatene er skjult av det anvendte filteret"
|
||||
"AllSearchResultsHiddenByFilter": "Alle resultatene er skjult av det anvendte filteret",
|
||||
"AptUpdater": "Bruk apt til å installere oppdateringen",
|
||||
"Discord": "Discord"
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@
|
||||
"TestAllApps": "Alle apps testen",
|
||||
"TestAllClients": "Test Alle Downloaders",
|
||||
"TestAllIndexers": "Test Alle Indexeerders",
|
||||
"TheLatestVersionIsAlreadyInstalled": "De nieuwste versie van {appName} is al geïnstalleerd",
|
||||
"OnLatestVersion": "De nieuwste versie van {appName} is al geïnstalleerd",
|
||||
"Time": "Tijd",
|
||||
"Title": "Titel",
|
||||
"Today": "Vandaag",
|
||||
@@ -386,7 +386,7 @@
|
||||
"UnableToAddANewIndexerProxyPleaseTryAgain": "Kan geen nieuwe Indexeerder-proxy toevoegen. Probeer het opnieuw.",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Kon geen nieuwe notificatie toevoegen, gelieve opnieuw te proberen.",
|
||||
"UnableToLoadAppProfiles": "Kan app-profielen niet laden",
|
||||
"UnableToLoadBackups": "Kon geen veiligheidskopieën laden",
|
||||
"BackupsLoadError": "Kon geen veiligheidskopieën laden",
|
||||
"UnableToLoadDevelopmentSettings": "Kan ontwikkelingsinstellingen niet laden",
|
||||
"DownloadClientsLoadError": "Downloaders kunnen niet worden geladen",
|
||||
"UnableToLoadGeneralSettings": "Kon Algemene instellingen niet inladen",
|
||||
@@ -500,5 +500,15 @@
|
||||
"Redirected": "Omleiden",
|
||||
"AllSearchResultsHiddenByFilter": "Alle resultaten zijn verborgen door het toegepaste filter",
|
||||
"Clone": "Kloon",
|
||||
"DownloadClientSettingsUrlBaseHelpText": "Voegt een voorvoegsel toe aan de {connectionName} url, zoals {url}"
|
||||
"DownloadClientSettingsUrlBaseHelpText": "Voegt een voorvoegsel toe aan de {connectionName} url, zoals {url}",
|
||||
"AptUpdater": "Gebruik apt om de update te installeren",
|
||||
"DockerUpdater": "Update de docker container om de update te ontvangen",
|
||||
"ErrorRestoringBackup": "Fout bij het herstellen van de back-up",
|
||||
"ExternalUpdater": "{appName} is geconfigureerd om een extern update mechanisme te gebruiken",
|
||||
"NoEventsFound": "Geen gebeurtenissen gevonden",
|
||||
"RestartReloadNote": "Aantekening: {appName} zal automatisch de Ui herstarten en herladen gedurende het herstel proces.",
|
||||
"UpdateAppDirectlyLoadError": "Kan {appName} niet rechtstreeks updaten,",
|
||||
"WouldYouLikeToRestoreBackup": "Wilt u de back-up {name} herstellen?",
|
||||
"Download": "Downloaden",
|
||||
"InstallLatest": "Installeer Nieuwste Versie"
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "Nie można dodać nowego indeksatora, spróbuj ponownie.",
|
||||
"UnableToAddANewIndexerProxyPleaseTryAgain": "Nie można dodać nowego indeksatora, spróbuj ponownie.",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Nie można dodać nowego powiadomienia, spróbuj ponownie.",
|
||||
"UnableToLoadBackups": "Nie można załadować kopii zapasowych",
|
||||
"BackupsLoadError": "Nie można załadować kopii zapasowych",
|
||||
"DownloadClientsLoadError": "Nie można załadować klientów pobierania",
|
||||
"UnableToLoadGeneralSettings": "Nie można załadować ustawień ogólnych",
|
||||
"UnableToLoadHistory": "Nie można załadować historii",
|
||||
@@ -341,7 +341,7 @@
|
||||
"ApplicationLongTermStatusCheckAllClientMessage": "Wszystkie indeksatory są niedostępne z powodu awarii przez ponad 6 godzin",
|
||||
"Remove": "Usunąć",
|
||||
"Replace": "Zastąpić",
|
||||
"TheLatestVersionIsAlreadyInstalled": "Najnowsza wersja {appName} jest już zainstalowana",
|
||||
"OnLatestVersion": "Najnowsza wersja {appName} jest już zainstalowana",
|
||||
"ApplicationURL": "Link do aplikacji",
|
||||
"ApplicationUrlHelpText": "Zewnętrzny URL tej aplikacji zawierający http(s)://, port i adres URL",
|
||||
"ApplyTagsHelpTextAdd": "Dodaj: dodaj tagi do istniejącej listy tagów",
|
||||
@@ -415,5 +415,14 @@
|
||||
"Connect": "Powiadomienia",
|
||||
"Episode": "odcinek",
|
||||
"Notifications": "Powiadomienia",
|
||||
"Publisher": "Wydawca"
|
||||
"Publisher": "Wydawca",
|
||||
"Download": "Ściągnij",
|
||||
"ErrorRestoringBackup": "Błąd podczas przywracania kopii zapasowej",
|
||||
"ExternalUpdater": "{appName} jest skonfigurowany do korzystania z zewnętrznego mechanizmu aktualizacji",
|
||||
"NoEventsFound": "Nie znaleziono wydarzeń",
|
||||
"RestartReloadNote": "Uwaga: {appName} automatycznie uruchomi się ponownie i przeładuje interfejs użytkownika podczas procesu przywracania.",
|
||||
"UpdateAppDirectlyLoadError": "Nie można bezpośrednio zaktualizować {appName},",
|
||||
"AptUpdater": "Użyj apt, aby zainstalować aktualizację",
|
||||
"DockerUpdater": "zaktualizuj kontener Dockera, aby otrzymać aktualizację",
|
||||
"InstallLatest": "Zainstaluj najnowsze"
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@
|
||||
"UnableToLoadGeneralSettings": "Não foi possível carregar as definições gerais",
|
||||
"DownloadClientsLoadError": "Não foi possível carregar os clientes de transferências",
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "Não foi possível adicionar um novo cliente de transferências, tenta novamente.",
|
||||
"UnableToLoadBackups": "Não foi possível carregar as cópias de segurança",
|
||||
"BackupsLoadError": "Não foi possível carregar as cópias de segurança",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Não foi possível adicionar uma nova notificação, tenta novamente.",
|
||||
"UISettings": "Definições da IU",
|
||||
"UILanguageHelpTextWarning": "É preciso reiniciar o browser",
|
||||
@@ -404,7 +404,7 @@
|
||||
"Queued": "Em fila",
|
||||
"Remove": "Remover",
|
||||
"Replace": "Substituir",
|
||||
"TheLatestVersionIsAlreadyInstalled": "A versão mais recente do {appName} já está instalada",
|
||||
"OnLatestVersion": "A versão mais recente do {appName} já está instalada",
|
||||
"AddSyncProfile": "Adicionar Perfil de Sincronização",
|
||||
"AddApplication": "Adicionar Aplicação",
|
||||
"AddCustomFilter": "Adicionar Filtro customizado",
|
||||
@@ -491,5 +491,15 @@
|
||||
"Script": "Script",
|
||||
"BuiltIn": "Incorporado",
|
||||
"PublishedDate": "Data de publicação",
|
||||
"AllSearchResultsHiddenByFilter": "Todos os resultados foram ocultados pelo filtro aplicado"
|
||||
"AllSearchResultsHiddenByFilter": "Todos os resultados foram ocultados pelo filtro aplicado",
|
||||
"BlackholeFolderHelpText": "Pasta em que {appName} guardará o ficheiro {extension}.",
|
||||
"AptUpdater": "Utilize o apt para instalar a atualização",
|
||||
"DockerUpdater": "atualize o contentor do Docker para receber a atualização",
|
||||
"Download": "Transferência",
|
||||
"ErrorRestoringBackup": "Erro ao restaurar cópia de segurança",
|
||||
"ExternalUpdater": "O {appName} está definido para usar um mecanismo de atualização externo",
|
||||
"NoEventsFound": "Nenhum evento encontrado",
|
||||
"RestartReloadNote": "Nota: o {appName} reiniciará e recarregará automaticamente a IU durante o processo de restauração.",
|
||||
"UpdateAppDirectlyLoadError": "Não foi possível atualizar o {appName} diretamente,",
|
||||
"InstallLatest": "Instalar o mais recente"
|
||||
}
|
||||
|
||||
@@ -429,7 +429,7 @@
|
||||
"TestAllApps": "Testar todos os aplicativos",
|
||||
"TestAllClients": "Testar todos os clientes",
|
||||
"TestAllIndexers": "Testar todos os indexadores",
|
||||
"TheLatestVersionIsAlreadyInstalled": "A versão mais recente do {appName} já está instalada",
|
||||
"OnLatestVersion": "A versão mais recente do {appName} já está instalada",
|
||||
"Theme": "Tema",
|
||||
"ThemeHelpText": "Alterar o tema da interface do usuário do aplicativo, o tema 'Auto' usará o tema do sistema operacional para definir o modo Claro ou Escuro. Inspirado por {inspiredBy}.",
|
||||
"Time": "Tempo",
|
||||
@@ -462,7 +462,7 @@
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Não foi possível adicionar uma nova notificação. Tente novamente.",
|
||||
"UnableToLoadAppProfiles": "Não foi possível carregar os perfis de aplicativos",
|
||||
"ApplicationsLoadError": "Não é possível carregar a lista de aplicativos",
|
||||
"UnableToLoadBackups": "Não foi possível carregar os backups",
|
||||
"BackupsLoadError": "Não foi possível carregar os backups",
|
||||
"UnableToLoadDevelopmentSettings": "Não foi possível carregar as configurações de desenvolvimento",
|
||||
"DownloadClientsLoadError": "Não foi possível carregar os clientes de download",
|
||||
"UnableToLoadGeneralSettings": "Não foi possível carregar as configurações gerais",
|
||||
@@ -784,5 +784,25 @@
|
||||
"IndexerAvistazSettingsUsernameHelpText": "Nome de Usuário do Site",
|
||||
"IndexerAvistazSettingsPasswordHelpText": "Senha do Site",
|
||||
"IndexerAvistazSettingsPidHelpText": "PID da página Minha Conta ou Meu Perfil",
|
||||
"IndexerAvistazSettingsUsernameHelpTextWarning": "Somente membros com rank e acima podem usar a API neste indexador."
|
||||
"IndexerAvistazSettingsUsernameHelpTextWarning": "Somente membros com rank e acima podem usar a API neste indexador.",
|
||||
"RestartReloadNote": "Observação: o {appName} reiniciará automaticamente e recarregará a interface durante o processo de restauração.",
|
||||
"DockerUpdater": "Atualize o contêiner docker para receber a atualização",
|
||||
"Download": "Baixar",
|
||||
"ErrorRestoringBackup": "Erro ao restaurar o backup",
|
||||
"ExternalUpdater": "O {appName} está configurado para usar um mecanismo de atualização externo",
|
||||
"FailedToFetchUpdates": "Falha ao buscar atualizações",
|
||||
"LogFilesLocation": "Os arquivos de log estão localizados em: {location}",
|
||||
"Logout": "Sair",
|
||||
"NoEventsFound": "Nenhum evento encontrado",
|
||||
"TheLogLevelDefault": "O nível de registro é padronizado como 'Info' e pode ser alterado em [Configurações Gerais](/settings/general)",
|
||||
"UpdateAppDirectlyLoadError": "Incapaz de atualizar o {appName} diretamente,",
|
||||
"UpdaterLogFiles": "Arquivos de log do atualizador",
|
||||
"WouldYouLikeToRestoreBackup": "Gostaria de restaurar o backup '{name}'?",
|
||||
"AptUpdater": "Usar apt para instalar atualizações",
|
||||
"Install": "Instalar",
|
||||
"InstallLatest": "Instalar o mais recente",
|
||||
"InstallMajorVersionUpdate": "Instalar Atualização",
|
||||
"InstallMajorVersionUpdateMessage": "Esta atualização instalará uma nova versão principal e pode não ser compatível com o seu sistema. Tem certeza de que deseja instalar esta atualização?",
|
||||
"InstallMajorVersionUpdateMessageLink": "Verifique [{domain}]({url}) para obter mais informações.",
|
||||
"FailedToFetchSettings": "Falha ao buscar configurações"
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
"TestAllClients": "Testați toți clienții",
|
||||
"Today": "Astăzi",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Imposibil de adăugat o nouă notificare, încercați din nou.",
|
||||
"UnableToLoadBackups": "Imposibil de încărcat copiile de rezervă",
|
||||
"BackupsLoadError": "Imposibil de încărcat copiile de rezervă",
|
||||
"DownloadClientsLoadError": "Nu se pot încărca clienții de descărcare",
|
||||
"URLBase": "Baza URL",
|
||||
"UrlBaseHelpText": "Pentru suport proxy invers, implicit este gol",
|
||||
@@ -329,7 +329,7 @@
|
||||
"IndexerHealthCheckNoIndexers": "Niciun indexator nu este activat, {appName} nu va returna rezultate la căutare.",
|
||||
"IndexerProxy": "Proxy indexator",
|
||||
"IndexerVipExpiredHealthCheckMessage": "Beneficiile VIP pentru indexator au expirat: {indexerNames}",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "Indexatorii nu au definiție și nu vor funcționa: {0}. Vă rugăm să-i ștergeți și (sau) să-i adăugați din nou în {appName}",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "Indexatorii nu au definiție și nu vor funcționa: {indexerNames}. Vă rugăm să-i ștergeți și (sau) să-i adăugați din nou în {appName}",
|
||||
"IndexerRss": "RSS indexator",
|
||||
"EnabledRedirected": "Activat, Redirecționat",
|
||||
"Ended": "Încheiat",
|
||||
@@ -374,7 +374,7 @@
|
||||
"NextExecution": "Următoarea execuție",
|
||||
"Remove": "Elimina",
|
||||
"Replace": "A inlocui",
|
||||
"TheLatestVersionIsAlreadyInstalled": "Cea mai recentă versiune a {appName} este deja instalată",
|
||||
"OnLatestVersion": "Cea mai recentă versiune a {appName} este deja instalată",
|
||||
"AddApplication": "Adaugă",
|
||||
"AddCustomFilter": "Adaugă filtru personalizat",
|
||||
"Track": "Urmă",
|
||||
@@ -477,5 +477,14 @@
|
||||
"InfoUrl": "URL informații",
|
||||
"PublishedDate": "Data publicării",
|
||||
"AllSearchResultsHiddenByFilter": "Toate rezultatele sunt ascunse de filtrul aplicat",
|
||||
"UpdateAvailableHealthCheckMessage": "O nouă versiune este disponibilă: {version}"
|
||||
"UpdateAvailableHealthCheckMessage": "O nouă versiune este disponibilă: {version}",
|
||||
"Download": "Descarca",
|
||||
"ErrorRestoringBackup": "Eroare la restaurarea copiei de rezervă",
|
||||
"UpdateAppDirectlyLoadError": "Imposibil de actualizat direct {appName},",
|
||||
"DockerUpdater": "Actualizați containerul Docker pentru a primi actualizarea",
|
||||
"ExternalUpdater": "{appName} este configurat pentru a utiliza un mecanism de actualizare extern",
|
||||
"NoEventsFound": "Nu s-au găsit evenimente",
|
||||
"RestartReloadNote": "Notă: {appName} va reporni și reîncărca automat interfața de utilizare în timpul procesului de restaurare.",
|
||||
"AptUpdater": "Utilizați apt pentru a instala actualizarea",
|
||||
"InstallLatest": "Instalați cel mai recent"
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
"Level": "Уровень",
|
||||
"Ok": "Ок",
|
||||
"AddDownloadClient": "Добавить клиент загрузки",
|
||||
"UpdateMechanismHelpText": "Использовать встроенный инструмент обновления {appName} или скрипт.",
|
||||
"UpdateMechanismHelpText": "Использовать встроенный инструмент обновления {appName} или скрипт",
|
||||
"IndexerStatusUnavailableHealthCheckMessage": "Индексаторы недоступны из-за ошибок: {indexerNames}",
|
||||
"NoTagsHaveBeenAddedYet": "Теги ещё не добавлены",
|
||||
"UnableToLoadTags": "Не удалось загрузить теги",
|
||||
@@ -255,7 +255,7 @@
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "Не удалось добавить новый индексатор, попробуйте ещё раз.",
|
||||
"UnableToAddANewIndexerProxyPleaseTryAgain": "Не удалось добавить новый прокси индексатора, попробуйте ещё раз.",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Не удалось добавить новое уведомление, попробуйте ещё раз.",
|
||||
"UnableToLoadBackups": "Не удалось загрузить резервные копии",
|
||||
"BackupsLoadError": "Не удалось загрузить резервные копии",
|
||||
"DownloadClientsLoadError": "Не удалось загрузить клиенты загрузки",
|
||||
"UnableToLoadGeneralSettings": "Не удалось загрузить общие настройки",
|
||||
"UnableToLoadNotifications": "Не удалось загрузить уведомления",
|
||||
@@ -351,7 +351,7 @@
|
||||
"ThemeHelpText": "Изменить тему интерфейса приложения. Тема 'Авто' будет использовать тему вашей ОС для выбора светлого или тёмного режима. Вдохновлено {inspiredBy}.",
|
||||
"Remove": "Удалить",
|
||||
"Replace": "Заменить",
|
||||
"TheLatestVersionIsAlreadyInstalled": "Последняя версия {appName} уже установлена",
|
||||
"OnLatestVersion": "Последняя версия {appName} уже установлена",
|
||||
"ApplicationURL": "URL-адрес приложения",
|
||||
"ApplicationUrlHelpText": "Внешний URL-адрес этого приложения, включая http(s)://, порт и базовый URL-адрес",
|
||||
"Label": "Метка",
|
||||
@@ -538,7 +538,7 @@
|
||||
"TotalIndexerSuccessfulGrabs": "Всего успешных захватов индексатора",
|
||||
"TotalIndexerQueries": "Всего запросов к индексатору",
|
||||
"TVSearchTypes": "Типы поиска ТВ-программ",
|
||||
"SyncLevelAddRemove": "Только добавление и удаление: при добавлении или удалении индексаторов из {appName} это удалённое приложение будет обновлено.",
|
||||
"SyncLevelAddRemove": "Только добавление и удаление: При добавлении или удалении индексаторов из {appName} это приложение будет автоматически обновлено.",
|
||||
"SyncProfiles": "Профили синхронизации",
|
||||
"TorznabUrl": "URL-адрес Torznab",
|
||||
"TotalGrabs": "Всего захватов",
|
||||
@@ -548,7 +548,7 @@
|
||||
"TotalUserAgentGrabs": "Всего захватов User Agent",
|
||||
"SyncProfile": "Профиль синхронизации",
|
||||
"TotalHostQueries": "Всего запросов к хосту",
|
||||
"SyncLevelFull": "Полная синхронизация: приложение будет поддерживать индексаторы полностью синхронизированными. Любые изменения, внесённые в индексаторы {appName}, будут синхронизированы с этим приложением.",
|
||||
"SyncLevelFull": "Полная синхронизация: Будет поддерживать индексаторы этого приложения полностью синхронизированными. Изменения, внесённые в индексаторы {appName}, будут синхронизированы с этим приложением. Любые изменения, внесённые в индексаторы удалённо в этом приложении, будут перезаписаны {appName} при следующей синхронизации.",
|
||||
"Menu": "Меню",
|
||||
"Artist": "Исполнитель",
|
||||
"OnGrabHelpText": "При захвате релиза",
|
||||
@@ -606,11 +606,11 @@
|
||||
"IndexerFileListSettingsPasskeyHelpText": "Passkey сайта (Это алфавитно-цифровая строка в URL трекера, отображаемая в вашем клиенте загрузки)",
|
||||
"IndexerGazelleGamesSettingsSearchGroupNames": "Поиск названий групп",
|
||||
"IndexerIPTorrentsSettingsCookieUserAgentHelpText": "User-Agent, используемый с cookie из браузера",
|
||||
"IndexerIPTorrentsSettingsFreeleechOnlyHelpText": "Искать только релизы freeleech",
|
||||
"IndexerIPTorrentsSettingsFreeleechOnlyHelpText": "Искать только релизы с freeleech",
|
||||
"AreYouSureYouWantToDeleteIndexer": "Вы уверены, что хотите удалить '{name}' из {appName}?",
|
||||
"BookSearch": "Поиск книг",
|
||||
"BookSearchTypes": "Типы поиска книг",
|
||||
"IndexerPassThePopcornSettingsFreeleechOnlyHelpText": "Искать только релизы freeleech",
|
||||
"IndexerPassThePopcornSettingsFreeleechOnlyHelpText": "Искать только релизы с freeleech",
|
||||
"IndexerSettingsGrabLimitHelpText": "Максимальное количество захватов, указанное соответствующей единицей, которое {appName} будет разрешать для сайта",
|
||||
"IndexerSettingsLimitsUnit": "Единица лимита",
|
||||
"IndexerSettingsLimitsUnitHelpText": "Единица времени для определения лимитов каждого индексатора",
|
||||
@@ -662,7 +662,7 @@
|
||||
"IndexerDetails": "Подробности индексатора",
|
||||
"EditCategory": "Редактировать категорию",
|
||||
"FoundCountReleases": "Найдено релизов: {itemCount}",
|
||||
"IndexerAlphaRatioSettingsFreeleechOnlyHelpText": "Искать только релизы freeleech",
|
||||
"IndexerAlphaRatioSettingsFreeleechOnlyHelpText": "Искать только релизы с freeleech",
|
||||
"IndexerBeyondHDSettingsLimitedOnly": "Только лимитированные",
|
||||
"IndexerBeyondHDSettingsRefundOnlyHelpText": "Искать только возвраты",
|
||||
"IndexerBeyondHDSettingsRewindOnlyHelpText": "Искать только повторы",
|
||||
@@ -677,7 +677,7 @@
|
||||
"NoIndexerCategories": "Нет категорий для этого индексатора",
|
||||
"IndexerVipExpiredHealthCheckMessage": "Привилегии VIP для индексатора истекли: {indexerNames}",
|
||||
"DefaultCategory": "Категория по умолчанию",
|
||||
"IndexerHDBitsSettingsFreeleechOnlyHelpText": "Показать только релизы freeleech",
|
||||
"IndexerHDBitsSettingsFreeleechOnlyHelpText": "Показать только релизы с freeleech",
|
||||
"IndexerHDBitsSettingsOrigins": "Источники",
|
||||
"IndexerNzbIndexSettingsApiKeyHelpText": "Ключ API сайта",
|
||||
"IndexerOrpheusSettingsApiKeyHelpText": "API ключ сайта (Находится в Настройки => Настройки доступа)",
|
||||
@@ -694,7 +694,7 @@
|
||||
"IndexerHDBitsSettingsUseFilenamesHelpText": "Выберите этот вариант, если хотите использовать имена файлов торрента в качестве названий релизов",
|
||||
"IndexerHDBitsSettingsUsernameHelpText": "Имя пользователя сайта",
|
||||
"IndexerSettingsCookieHelpText": "Cookie сайта",
|
||||
"IndexerSettingsFreeleechOnly": "Только Freeleech",
|
||||
"IndexerSettingsFreeleechOnly": "Только с freeleech",
|
||||
"IndexerSettingsPasskey": "Pass Key",
|
||||
"IndexerId": "ID индексатора",
|
||||
"DeleteSelectedIndexers": "Удалить выбранные индексаторы",
|
||||
@@ -737,9 +737,9 @@
|
||||
"ClickToChangeQueryOptions": "Нажмите, чтобы изменить параметры запроса",
|
||||
"DownloadClientSettingsDefaultCategorySubFolderHelpText": "Категория по умолчанию, если для релиза нет соответствующей категории. Создание определённой категории для {appName}, позволяет избежать конфликтов с загрузками, не связанными с {appName}. Использование категории не обязательно, но настоятельно рекомендуется. Создаёт подкаталог [category] в каталоге вывода.",
|
||||
"AverageQueries": "Среднее количество запросов",
|
||||
"IndexerGazelleGamesSettingsFreeleechOnlyHelpText": "Искать только релизы freeleech",
|
||||
"IndexerGazelleGamesSettingsFreeleechOnlyHelpText": "Искать только релизы с freeleech",
|
||||
"IndexerMTeamTpSettingsApiKeyHelpText": "Ключ API сайта (Находится в Панели управления пользователя => Безопасность => Лаборатория)",
|
||||
"IndexerMTeamTpSettingsFreeleechOnlyHelpText": "Искать только релизы freeleech",
|
||||
"IndexerMTeamTpSettingsFreeleechOnlyHelpText": "Искать только релизы с freeleech",
|
||||
"ProwlarrDownloadClientsAlert": "Если вы намерены выполнять поиск непосредственно в {appName}, вам необходимо добавить клиенты загрузки. В противном случае, добавлять их здесь не нужно. Для поиска из ваших приложений используются клиенты загрузки, которые настроены в самих приложениях.",
|
||||
"ProwlarrDownloadClientsInAppOnlyAlert": "Клиенты загрузки предназначены только для поиска внутри приложения {appName} и не синхронизируются с другими приложениями. Мы не планируем добавлять функцию синхронизации.",
|
||||
"ProwlarrSupportsAnyIndexer": "{appName} поддерживает множество индексаторов, а также любой индексатор, использующий стандарт Newznab/Torznab, с помощью 'Generic Newznab' (для Usenet) или 'Generic Torznab' (для торрентов). Выберите и добавьте свой индексатор из списка ниже.",
|
||||
@@ -747,14 +747,14 @@
|
||||
"DownloadClientSettingsDefaultCategoryHelpText": "Категория по умолчанию, если для релиза нет соответствующей категории. Создание определённой категории для {appName}, позволяет избежать конфликтов с загрузками, не связанными с {appName}. Использование категории не обязательно, но настоятельно рекомендуется.",
|
||||
"DownloadClientSettingsPriorityItemHelpText": "Приоритет, используемый при захвате элементов",
|
||||
"GrabTitle": "Захватить название",
|
||||
"IndexerBeyondHDSettingsFreeleechOnlyHelpText": "Искать только релизы freeleech",
|
||||
"IndexerBeyondHDSettingsLimitedOnlyHelpText": "Искать только freeleech (Лимитированная отдача)",
|
||||
"IndexerBeyondHDSettingsFreeleechOnlyHelpText": "Искать только релизы с freeleech",
|
||||
"IndexerBeyondHDSettingsLimitedOnlyHelpText": "Искать только с freeleech (Лимитированная отдача)",
|
||||
"IndexerBeyondHDSettingsRefundOnly": "Только возврат",
|
||||
"IndexerBeyondHDSettingsRssKeyHelpText": "Ключ RSS с сайта (Находится в Моя безопасность => Ключ RSS)",
|
||||
"IndexerDownloadClientHelpText": "Определите клиент загрузки, используемый для загрузки из этого индексатора в {appName}.",
|
||||
"NewznabUrl": "URL-адрес Newznab",
|
||||
"SeedTimeHelpText": "Время, в течение которого торрент должен оставаться на раздаче перед остановкой, пусто — используется значение приложения по умолчанию",
|
||||
"IndexerFileListSettingsFreeleechOnlyHelpText": "Искать только релизы freeleech",
|
||||
"IndexerFileListSettingsFreeleechOnlyHelpText": "Искать только релизы с freeleech",
|
||||
"IndexerFileListSettingsUsernameHelpText": "Имя пользователя сайта",
|
||||
"IndexerHealthCheckNoIndexers": "Нет включённых индексаторов, {appName} не будет возвращать результаты поиска",
|
||||
"IndexerObsoleteCheckMessage": "Индексаторы: {0} устарели или были обновлены. Удалите их из {appName} и (или) добавьте снова",
|
||||
@@ -783,6 +783,26 @@
|
||||
"IndexerPassThePopcornSettingsGoldenPopcornOnlyHelpText": "Искать релизы только Golden Popcorn",
|
||||
"PreferMagnetUrl": "Предпочитать Magnet URL",
|
||||
"PreferMagnetUrlHelpText": "При включении этот индексатор предпочтёт использовать для загрузки magnet URL, с возможностью перехода на торрент-ссылки",
|
||||
"IndexerAvistazSettingsFreeleechOnlyHelpText": "Искать только релизы freeleech",
|
||||
"IndexerAvistazSettingsUsernameHelpText": "Имя пользователя сайта"
|
||||
"IndexerAvistazSettingsFreeleechOnlyHelpText": "Искать только релизы с freeleech",
|
||||
"IndexerAvistazSettingsUsernameHelpText": "Имя пользователя сайта",
|
||||
"AptUpdater": "Использовать apt для установки обновления",
|
||||
"Download": "Загрузить",
|
||||
"ErrorRestoringBackup": "Ошибка восстановления резервной копии",
|
||||
"FailedToFetchUpdates": "Не удалось загрузить обновления",
|
||||
"LogFilesLocation": "Файлы журнала расположены в: {location}",
|
||||
"Logout": "Завершить сеанс",
|
||||
"UpdateAppDirectlyLoadError": "Обновление {appName} напрямую невозможно,",
|
||||
"DockerUpdater": "Обновите контейнер Docker, чтобы получить обновление",
|
||||
"ExternalUpdater": "{appName} настроен на использование внешнего механизма обновления",
|
||||
"NoEventsFound": "Событий не найдено",
|
||||
"RestartReloadNote": "Примечание: {appName} автоматически перезапустится и перезагрузит интерфейс пользователя во время процесса восстановления.",
|
||||
"TheLogLevelDefault": "Уровень журналирования по умолчанию установлен на 'Информация' и может быть изменён в [Общих настройках](/settings/general)",
|
||||
"UpdaterLogFiles": "Файлы журнала обновления",
|
||||
"WouldYouLikeToRestoreBackup": "Хотите восстановить резервную копию '{name}'?",
|
||||
"Install": "Установить",
|
||||
"InstallLatest": "Установить последнюю",
|
||||
"InstallMajorVersionUpdateMessageLink": "Для получения дополнительной информации посетите [{domain}]({url}).",
|
||||
"InstallMajorVersionUpdate": "Установить обновление",
|
||||
"InstallMajorVersionUpdateMessage": "Это обновление установит новую версию, которая может не поддерживаться вашей системой. Вы уверены, что хотите установить это обновление?",
|
||||
"FailedToFetchSettings": "Не удалось загрузить настройки"
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "Nie je možné pridať novú podmienku, skúste to znova.",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Nie je možné pridať novú podmienku, skúste to znova.",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "Nie je možné pridať novú podmienku, skúste to znova.",
|
||||
"UnableToLoadBackups": "Nie je možné načítať albumy",
|
||||
"BackupsLoadError": "Nie je možné načítať albumy",
|
||||
"Docker": "Docker",
|
||||
"UnableToAddANewApplicationPleaseTryAgain": "Nie je možné pridať novú podmienku, skúste to znova.",
|
||||
"EditIndexerImplementation": "Pridať Indexer - {implementationName}",
|
||||
@@ -145,5 +145,7 @@
|
||||
"EditApplicationImplementation": "Pridať podmienku - {implementationName}",
|
||||
"UnableToAddANewAppProfilePleaseTryAgain": "Nie je možné pridať novú podmienku, skúste to znova.",
|
||||
"BuiltIn": "Vstavaný",
|
||||
"AllSearchResultsHiddenByFilter": "Použitý filter skryje všetky výsledky"
|
||||
"AllSearchResultsHiddenByFilter": "Použitý filter skryje všetky výsledky",
|
||||
"AptUpdater": "Použiť apt pre inštaláciu aktualizácie",
|
||||
"Discord": "Discord"
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@
|
||||
"Torrent": "Torrenter",
|
||||
"UILanguage": "UI-språk",
|
||||
"UnableToAddANewApplicationPleaseTryAgain": "Det gick inte att lägga till ett nytt meddelande, försök igen.",
|
||||
"UnableToLoadBackups": "Det gick inte att ladda säkerhetskopior",
|
||||
"BackupsLoadError": "Det gick inte att ladda säkerhetskopior",
|
||||
"UnableToAddANewIndexerProxyPleaseTryAgain": "Inte möjligt att lägga till en ny indexerare, var god försök igen.",
|
||||
"UnableToLoadGeneralSettings": "Det går inte att läsa in allmänna inställningar",
|
||||
"New": "Ny",
|
||||
@@ -402,7 +402,7 @@
|
||||
"Queued": "Köad",
|
||||
"Remove": "Ta bort",
|
||||
"Replace": "Ersätta",
|
||||
"TheLatestVersionIsAlreadyInstalled": "Den senaste versionen av {appName} är redan installerad",
|
||||
"OnLatestVersion": "Den senaste versionen av {appName} är redan installerad",
|
||||
"ApplicationURL": "Applikations-URL",
|
||||
"ApplicationUrlHelpText": "Denna applikations externa URL inklusive http(s)://, port och URL-bas",
|
||||
"Episode": "Avsnitt",
|
||||
@@ -449,5 +449,14 @@
|
||||
"Script": "Skript",
|
||||
"PublishedDate": "Publiceringsdatum",
|
||||
"Redirected": "Omdirigera",
|
||||
"AllSearchResultsHiddenByFilter": "Alla resultat döljs av det tillämpade filtret"
|
||||
"AllSearchResultsHiddenByFilter": "Alla resultat döljs av det tillämpade filtret",
|
||||
"DockerUpdater": "uppdatera dockerbehållaren för att ta emot uppdateringen",
|
||||
"ErrorRestoringBackup": "Fel vid återställning av säkerhetskopian",
|
||||
"NoEventsFound": "Inga händelser hittades",
|
||||
"RestartReloadNote": "Obs! {appName} startar automatiskt om och laddar om användargränssnittet under återställningsprocessen.",
|
||||
"UpdateAppDirectlyLoadError": "Det går inte att uppdatera {appName} direkt,",
|
||||
"AptUpdater": "Använd apt för att installera uppdateringen",
|
||||
"Download": "Ladda ner",
|
||||
"ExternalUpdater": "{appName} är konfigurerad för att använda en extern uppdateringsmekanism",
|
||||
"InstallLatest": "Installera senaste"
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
"SelectAll": "เลือกทั้งหมด",
|
||||
"SystemTimeCheckMessage": "เวลาของระบบปิดมากกว่า 1 วัน งานที่ตั้งเวลาไว้อาจทำงานไม่ถูกต้องจนกว่าจะมีการแก้ไขเวลา",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "ไม่สามารถเพิ่มการแจ้งเตือนใหม่โปรดลองอีกครั้ง",
|
||||
"UnableToLoadBackups": "ไม่สามารถโหลดข้อมูลสำรอง",
|
||||
"BackupsLoadError": "ไม่สามารถโหลดข้อมูลสำรอง",
|
||||
"UnableToLoadNotifications": "ไม่สามารถโหลดการแจ้งเตือน",
|
||||
"ApplicationStatusCheckAllClientMessage": "รายการทั้งหมดไม่พร้อมใช้งานเนื่องจากความล้มเหลว",
|
||||
"ApplicationStatusCheckSingleClientMessage": "รายการไม่พร้อมใช้งานเนื่องจากความล้มเหลว: {0}",
|
||||
@@ -329,7 +329,7 @@
|
||||
"Queued": "อยู่ในคิว",
|
||||
"Remove": "ลบ",
|
||||
"Replace": "แทนที่",
|
||||
"TheLatestVersionIsAlreadyInstalled": "มีการติดตั้ง {appName} เวอร์ชันล่าสุดแล้ว",
|
||||
"OnLatestVersion": "มีการติดตั้ง {appName} เวอร์ชันล่าสุดแล้ว",
|
||||
"Track": "ติดตาม",
|
||||
"DeleteSelectedApplicationsMessageText": "แน่ใจไหมว่าต้องการลบตัวสร้างดัชนี \"{0}\"",
|
||||
"ApplyTagsHelpTextAdd": "เพิ่ม: เพิ่มแท็กในรายการแท็กที่มีอยู่",
|
||||
@@ -364,5 +364,14 @@
|
||||
"Script": "สคริปต์",
|
||||
"BuiltIn": "สร้างขึ้นใน",
|
||||
"PublishedDate": "วันที่เผยแพร่",
|
||||
"AllSearchResultsHiddenByFilter": "ผลลัพธ์ทั้งหมดถูกซ่อนโดยตัวกรองที่ใช้"
|
||||
"AllSearchResultsHiddenByFilter": "ผลลัพธ์ทั้งหมดถูกซ่อนโดยตัวกรองที่ใช้",
|
||||
"AptUpdater": "ใช้ apt เพื่อติดตั้งการอัปเดต",
|
||||
"Download": "ดาวน์โหลด",
|
||||
"ErrorRestoringBackup": "เกิดข้อผิดพลาดในการกู้คืนข้อมูลสำรอง",
|
||||
"DockerUpdater": "อัปเดตคอนเทนเนอร์นักเทียบท่าเพื่อรับการอัปเดต",
|
||||
"ExternalUpdater": "{appName} ถูกกำหนดค่าให้ใช้กลไกการอัพเดตภายนอก",
|
||||
"NoEventsFound": "ไม่พบกิจกรรม",
|
||||
"RestartReloadNote": "หมายเหตุ: {appName} จะรีสตาร์ทและโหลด UI ใหม่โดยอัตโนมัติในระหว่างกระบวนการกู้คืน",
|
||||
"UpdateAppDirectlyLoadError": "ไม่สามารถอัปเดต {appName} ได้โดยตรง",
|
||||
"InstallLatest": "ติดตั้งล่าสุด"
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "Yeni bir dizinleyici eklenemiyor, lütfen tekrar deneyin.",
|
||||
"UnableToAddANewIndexerProxyPleaseTryAgain": "Yeni bir dizinleyici eklenemiyor, lütfen tekrar deneyin.",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Yeni bir bildirim eklenemiyor, lütfen tekrar deneyin.",
|
||||
"UnableToLoadBackups": "Yedeklemeler yüklenemiyor",
|
||||
"BackupsLoadError": "Yedeklemeler yüklenemiyor",
|
||||
"UnableToLoadHistory": "Geçmiş yüklenemiyor",
|
||||
"UnableToLoadNotifications": "Bildirimler yüklenemiyor",
|
||||
"UnableToLoadUISettings": "UI ayarları yüklenemiyor",
|
||||
@@ -259,7 +259,7 @@
|
||||
"Indexer": "Dizinleyici",
|
||||
"DownloadClientStatusAllClientHealthCheckMessage": "Hatalar nedeniyle tüm indirme istemcileri kullanılamıyor",
|
||||
"EditIndexer": "Dizinleyiciyi Düzenle",
|
||||
"Enable": "etkinleştirme",
|
||||
"Enable": "Etkinleştir",
|
||||
"EnableInteractiveSearch": "Etkileşimli Aramayı Etkinleştir",
|
||||
"EnableRss": "RSS'yi etkinleştir",
|
||||
"EnableSSL": "SSL'yi etkinleştir",
|
||||
@@ -332,7 +332,7 @@
|
||||
"ApplicationLongTermStatusCheckSingleClientMessage": "6 saatten uzun süredir yaşanan arızalar nedeniyle dizinleyiciler kullanılamıyor: {0}",
|
||||
"Remove": "Kaldır",
|
||||
"Replace": "Değiştir",
|
||||
"TheLatestVersionIsAlreadyInstalled": "{appName}'ın en son sürümü zaten kurulu",
|
||||
"OnLatestVersion": "{appName}'ın en son sürümü zaten kurulu",
|
||||
"ApplyTagsHelpTextAdd": "Ekle: Etiketleri mevcut etiket listesine ekleyin",
|
||||
"ApplyTagsHelpTextHowToApplyApplications": "Seçilen filmlere etiketler nasıl uygulanır",
|
||||
"ApplyTagsHelpTextRemove": "Kaldır: Girilen etiketleri kaldırın",
|
||||
@@ -536,5 +536,26 @@
|
||||
"HealthMessagesInfoBox": "Satırın sonundaki wiki bağlantısını (kitap simgesi) tıklayarak veya [günlüklerinizi]({link}) kontrol ederek bu durum kontrolü mesajlarının nedeni hakkında daha fazla bilgi bulabilirsiniz. Bu mesajları yorumlamakta zorluk yaşıyorsanız aşağıdaki bağlantılardan destek ekibimize ulaşabilirsiniz.",
|
||||
"PackageVersionInfo": "{packageAuthor} tarafından {packageVersion}",
|
||||
"LogSizeLimit": "Log Boyutu Sınırı",
|
||||
"LogSizeLimitHelpText": "Arşivlemeden önce MB cinsinden maksimum log dosya boyutu. Varsayılan 1 MB'tır."
|
||||
"LogSizeLimitHelpText": "Arşivlemeden önce MB cinsinden maksimum log dosya boyutu. Varsayılan 1 MB'tır.",
|
||||
"AptUpdater": "Güncellemeyi yüklemek için apt kullanın",
|
||||
"Download": "İndir",
|
||||
"ErrorRestoringBackup": "Yedeği geri yüklerken hata",
|
||||
"ExternalUpdater": "{appName}, harici bir güncelleme mekanizması kullanacak şekilde yapılandırıldı",
|
||||
"LogFilesLocation": "Günlük dosyaları şu konumda bulunur: {location}",
|
||||
"NoEventsFound": "Etkinlik bulunamadı",
|
||||
"RestartReloadNote": "Not: {appName}, geri yükleme işlemi sırasında kullanıcı arayüzünü otomatik olarak yeniden başlatacak ve yeniden yükleyecektir.",
|
||||
"TheLogLevelDefault": "Günlük düzeyi varsayılan olarak 'Bilgi' şeklindedir ve [Genel Ayarlar](/settings/general) bölümünden değiştirilebilir",
|
||||
"UpdateAppDirectlyLoadError": "{appName} doğrudan güncellenemiyor,",
|
||||
"DockerUpdater": "güncellemeyi almak için docker konteynerini güncelleyin",
|
||||
"FailedToFetchUpdates": "Güncellemeler getirilemedi",
|
||||
"Logout": "Çıkış",
|
||||
"UpdaterLogFiles": "Güncelleme Günlük Dosyaları",
|
||||
"WouldYouLikeToRestoreBackup": "'{name}' yedeğini geri yüklemek ister misiniz?",
|
||||
"InstallLatest": "En Sonu Yükle",
|
||||
"Install": "Kur",
|
||||
"InstallMajorVersionUpdate": "Güncellemeyi Kur",
|
||||
"InstallMajorVersionUpdateMessage": "Bu güncelleştirme yeni bir ana sürüm yükleyecek ve sisteminizle uyumlu olmayabilir. Bu güncelleştirmeyi yüklemek istediğinizden emin misiniz?",
|
||||
"InstallMajorVersionUpdateMessageLink": "Daha fazla bilgi için lütfen [{domain}]({url}) adresini kontrol edin.",
|
||||
"Season": "Sezon",
|
||||
"Artist": "sanatçı"
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
"UILanguageHelpTextWarning": "Потрібно перезавантажити браузер",
|
||||
"UnableToAddANewIndexerPleaseTryAgain": "Не вдалося додати новий індексатор, спробуйте ще раз.",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Не вдалося додати нове сповіщення, спробуйте ще раз.",
|
||||
"UnableToLoadBackups": "Не вдалося завантажити резервні копії",
|
||||
"BackupsLoadError": "Не вдалося завантажити резервні копії",
|
||||
"UnableToLoadUISettings": "Не вдалося завантажити налаштування інтерфейсу користувача",
|
||||
"UnsavedChanges": "Незбережені зміни",
|
||||
"UnselectAll": "Скасувати вибір усіх",
|
||||
@@ -336,7 +336,7 @@
|
||||
"ApplicationLongTermStatusCheckSingleClientMessage": "Індексатори недоступні через збої більше 6 годин: {0}",
|
||||
"Remove": "Видалити",
|
||||
"Replace": "Замінити",
|
||||
"TheLatestVersionIsAlreadyInstalled": "Остання версія {appName} вже встановлена",
|
||||
"OnLatestVersion": "Остання версія {appName} вже встановлена",
|
||||
"ApplicationURL": "URL програми",
|
||||
"Theme": "Тема",
|
||||
"ApplyTagsHelpTextAdd": "Додати: додати теги до наявного списку тегів",
|
||||
@@ -427,5 +427,14 @@
|
||||
"Any": "Будь-який",
|
||||
"BuiltIn": "Вбудований",
|
||||
"PublishedDate": "Дата публікації",
|
||||
"AllSearchResultsHiddenByFilter": "Всі результати приховані фільтром"
|
||||
"AllSearchResultsHiddenByFilter": "Всі результати приховані фільтром",
|
||||
"AptUpdater": "Використовуйте apt для інсталяції оновлення",
|
||||
"DockerUpdater": "Оновіть контейнер docker, щоб отримати оновлення",
|
||||
"UpdateAppDirectlyLoadError": "Неможливо оновити {appName} безпосередньо,",
|
||||
"Download": "Завантажити",
|
||||
"ErrorRestoringBackup": "Помилка відновлення резервної копії",
|
||||
"ExternalUpdater": "{appName} налаштовано на використання зовнішнього механізму оновлення",
|
||||
"NoEventsFound": "Подій не знайдено",
|
||||
"RestartReloadNote": "Примітка: {appName} автоматично перезапуститься та перезавантажить інтерфейс під час процесу відновлення.",
|
||||
"InstallLatest": "Встановити останній"
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
"UnableToAddANewDownloadClientPleaseTryAgain": "Không thể thêm ứng dụng khách tải xuống mới, vui lòng thử lại.",
|
||||
"UnableToAddANewIndexerProxyPleaseTryAgain": "Không thể thêm trình chỉ mục mới, vui lòng thử lại.",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "Không thể thêm thông báo mới, vui lòng thử lại.",
|
||||
"UnableToLoadBackups": "Không thể tải các bản sao lưu",
|
||||
"BackupsLoadError": "Không thể tải các bản sao lưu",
|
||||
"DownloadClientsLoadError": "Không thể tải ứng dụng khách tải xuống",
|
||||
"UnableToLoadGeneralSettings": "Không thể tải Cài đặt chung",
|
||||
"UnableToLoadHistory": "Không thể tải lịch sử",
|
||||
@@ -329,7 +329,7 @@
|
||||
"Queued": "Đã xếp hàng",
|
||||
"Remove": "Tẩy",
|
||||
"Replace": "Thay thế",
|
||||
"TheLatestVersionIsAlreadyInstalled": "Phiên bản mới nhất của {appName} đã được cài đặt",
|
||||
"OnLatestVersion": "Phiên bản mới nhất của {appName} đã được cài đặt",
|
||||
"ApplyChanges": "Áp dụng thay đổi",
|
||||
"ApplyTagsHelpTextAdd": "Thêm: Thêm thẻ vào danh sách thẻ hiện có",
|
||||
"ApplyTagsHelpTextHowToApplyApplications": "Cách áp dụng thẻ cho các phim đã chọn",
|
||||
@@ -363,5 +363,30 @@
|
||||
"BuiltIn": "Được xây dựng trong",
|
||||
"Script": "Kịch bản",
|
||||
"PublishedDate": "Ngày xuất bản",
|
||||
"AllSearchResultsHiddenByFilter": "Tất cả kết quả bị ẩn bởi bộ lọc được áp dụng"
|
||||
"AllSearchResultsHiddenByFilter": "Tất cả kết quả bị ẩn bởi bộ lọc được áp dụng",
|
||||
"AptUpdater": "Sử dụng apt để cài đặt bản cập nhật",
|
||||
"DockerUpdater": "cập nhật vùng chứa docker để nhận bản cập nhật",
|
||||
"Download": "Tải xuống",
|
||||
"NoEventsFound": "Không tìm thấy sự kiện",
|
||||
"ErrorRestoringBackup": "Lỗi khi khôi phục bản sao lưu",
|
||||
"ExternalUpdater": "{appName} được định cấu hình để sử dụng cơ chế cập nhật bên ngoài",
|
||||
"RestartReloadNote": "Lưu ý: {appName} sẽ tự động khởi động lại và tải lại giao diện người dùng trong quá trình khôi phục.",
|
||||
"UpdateAppDirectlyLoadError": "Không thể cập nhật {appName} trực tiếp,",
|
||||
"InstallLatest": "Cài đặt mới nhất",
|
||||
"AuthenticationMethodHelpTextWarning": "Vui lòng chọn một phương thức xác thực hợp lệ",
|
||||
"AuthenticationRequiredPasswordHelpTextWarning": "Nhập mật khẩu mới",
|
||||
"AuthenticationRequiredUsernameHelpTextWarning": "Nhập tên người dùng mới",
|
||||
"UpdaterLogFiles": "Tệp nhật ký của trình cập nhật",
|
||||
"UseSsl": "Dùng SSL",
|
||||
"AppUpdatedVersion": "{appName} đã được cập nhật lên phiên bản `{version}`, để nhận được những thay đổi mới nhất, bạn cần tải lại {appName}",
|
||||
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Xác nhận mật khẩu mới",
|
||||
"UpdateAvailableHealthCheckMessage": "Có cập nhật mới: {version}",
|
||||
"AuthenticationRequiredWarning": "Để ngăn truy cập từ xa mà không cần xác thực, {appName} hiện yêu cầu bật xác thực. Bạn có thể tùy ý tắt xác thực từ các địa chỉ cục bộ.",
|
||||
"AuthenticationRequired": "Bắt buộc phải xác thực",
|
||||
"AuthenticationMethod": "Phương thức xác thực",
|
||||
"AddDownloadClientImplementation": "Thêm trình tải xuống - {implementationName}",
|
||||
"AddIndexerImplementation": "Thêm trình lập chỉ mục - {implementationName}",
|
||||
"AddConnection": "Thêm kết nối",
|
||||
"AddConnectionImplementation": "Thêm điều kiện - {implementationName}",
|
||||
"AppUpdated": "{appName} đã cập nhật"
|
||||
}
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
"AddRemoveOnly": "仅添加和删除",
|
||||
"AddSyncProfile": "添加同步配置文件",
|
||||
"AddToDownloadClient": "添加发布到下载客户端",
|
||||
"Added": "已添加",
|
||||
"Added": "添加日期",
|
||||
"AddedToDownloadClient": "发布已添加档案到客户端",
|
||||
"AddingTag": "添加标签",
|
||||
"Age": "年龄",
|
||||
"All": "全部",
|
||||
"AllIndexersHiddenDueToFilter": "由于应用了筛选器,所有索引器都被隐藏。",
|
||||
"Analytics": "分析",
|
||||
"AnalyticsEnabledHelpText": "将匿名使用情况和错误信息发送到{appName}的服务器。这包括有关您的浏览器的信息、您使用的{appName} WebUI页面、错误报告以及操作系统和运行时版本。我们将使用此信息来确定功能和错误修复的优先级。",
|
||||
"AnalyticsEnabledHelpText": "将匿名使用情况和错误信息发送到 {appName} 的服务器。这包括有关您的浏览器信息、您使用的 {appName} WebUI页面、错误报告以及操作系统和运行时版本。我们将使用此信息来确定功能和错误修复的优先级。",
|
||||
"ApiKey": "API 密钥",
|
||||
"ApiKeyValidationHealthCheckMessage": "请将API密钥更新为至少 {length} 个字符长。您可以通过设置或配置文件完成此操作",
|
||||
"AppDataDirectory": "AppData 目录",
|
||||
@@ -89,7 +89,7 @@
|
||||
"ConnectSettingsSummary": "通知和自定义脚本",
|
||||
"ConnectionLost": "连接丢失",
|
||||
"Connections": "连接",
|
||||
"CouldNotConnectSignalR": "无法连接至SignalR,不会升级UI",
|
||||
"CouldNotConnectSignalR": "无法连接至 SignalR,UI 将不会更新",
|
||||
"Custom": "自定义",
|
||||
"CustomFilters": "自定义过滤器",
|
||||
"DatabaseMigration": "数据库迁移版本",
|
||||
@@ -101,14 +101,14 @@
|
||||
"DeleteApplication": "删除应用程序",
|
||||
"DeleteApplicationMessageText": "您确定要删除应用程序“{name}”吗?",
|
||||
"DeleteBackup": "删除备份",
|
||||
"DeleteBackupMessageText": "您确定要删除备份“{name}”吗?",
|
||||
"DeleteBackupMessageText": "您确定要删除备份 “{name}” 吗?",
|
||||
"DeleteClientCategory": "删除下载客户端分类",
|
||||
"DeleteDownloadClient": "删除下载客户端",
|
||||
"DeleteDownloadClientMessageText": "你确定要删除下载客户端 “{name}” 吗?",
|
||||
"DeleteDownloadClientMessageText": "您确定要删除下载客户端 “{name}” 吗?",
|
||||
"DeleteIndexerProxy": "删除搜刮器代理",
|
||||
"DeleteIndexerProxyMessageText": "您确定要删除索引器代理“{name}”吗?",
|
||||
"DeleteNotification": "删除消息推送",
|
||||
"DeleteNotificationMessageText": "您确定要删除通知“{name}”吗?",
|
||||
"DeleteNotificationMessageText": "您确定要删除通知 “{name}” 吗?",
|
||||
"DeleteTag": "删除标签",
|
||||
"DeleteTagMessageText": "您确定要删除标签 '{label}' 吗?",
|
||||
"Description": "描述",
|
||||
@@ -133,7 +133,7 @@
|
||||
"ElapsedTime": "运行时间",
|
||||
"Enable": "启用",
|
||||
"EnableAutomaticSearch": "启用自动搜索",
|
||||
"EnableAutomaticSearchHelpText": "当自动搜索通过UI或{appName}执行时将被使用",
|
||||
"EnableAutomaticSearchHelpText": "当自动搜索通过 UI 或 {appName} 执行时将被使用",
|
||||
"EnableIndexer": "启用搜刮器",
|
||||
"EnableInteractiveSearch": "启用手动搜索",
|
||||
"EnableInteractiveSearchHelpText": "当手动搜索启用时使用",
|
||||
@@ -200,7 +200,7 @@
|
||||
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "由于故障超过6小时,所有搜刮器均不可用",
|
||||
"IndexerLongTermStatusUnavailableHealthCheckMessage": "由于故障6小时,下列搜刮器都已不可用:{indexerNames}",
|
||||
"IndexerName": "索引名字",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "索引器没有定义,将无法工作: {0}. 请删除或重新添加到{appName}",
|
||||
"IndexerNoDefinitionCheckHealthCheckMessage": "索引器没有定义,将无法工作: {indexerNames}. 请删除或重新添加到{appName}",
|
||||
"IndexerObsoleteCheckMessage": "搜刮器已过弃用或已更新:{0}。请将其删除和(或)重新添加到 {appName}",
|
||||
"IndexerPriority": "搜刮器优先级",
|
||||
"IndexerPriorityHelpText": "索引器优先级从1(最高)到50(最低),默认25。",
|
||||
@@ -307,7 +307,7 @@
|
||||
"ProwlarrSupportsAnyIndexer": "{appName}支持多种搜刮器,包括任何使用Newznab/Torznab标准的搜刮器(“通用Newznab”对应Usenet,“Generic Torznab”对应Torrents)。从以下搜索并选择你的搜刮器。",
|
||||
"Proxies": "代理",
|
||||
"Proxy": "代理",
|
||||
"ProxyBypassFilterHelpText": "使用“ , ”作为分隔符,和“ *. ”作为二级域名的通配符",
|
||||
"ProxyBypassFilterHelpText": "使用 “ , ” 作为分隔符,并使用 “ *. ” 作为二级域名的通配符",
|
||||
"ProxyBadRequestHealthCheckMessage": "测试代理失败。状态码:{statusCode}",
|
||||
"ProxyFailedToTestHealthCheckMessage": "测试代理失败: {url}",
|
||||
"ProxyResolveIpHealthCheckMessage": "无法解析已设置的代理服务器主机{proxyHostName}的IP地址",
|
||||
@@ -426,7 +426,7 @@
|
||||
"TestAllApps": "测试全部应用",
|
||||
"TestAllClients": "测试全部客户端",
|
||||
"TestAllIndexers": "测试全部索引器",
|
||||
"TheLatestVersionIsAlreadyInstalled": "已安装最新版本的{appName}",
|
||||
"OnLatestVersion": "已安装最新版本的{appName}",
|
||||
"Theme": "主题",
|
||||
"ThemeHelpText": "更改应用程序UI主题,“自动”主题将使用您的操作系统主题设置亮或暗模式。灵感来源于{inspirredby}。",
|
||||
"Time": "时间",
|
||||
@@ -451,7 +451,7 @@
|
||||
"UnableToAddANewIndexerProxyPleaseTryAgain": "无法添加搜刮器,请稍后重试。",
|
||||
"UnableToAddANewNotificationPleaseTryAgain": "无法添加新通知,请稍后重试。",
|
||||
"UnableToLoadAppProfiles": "无法加载应用配置",
|
||||
"UnableToLoadBackups": "无法加载备份",
|
||||
"BackupsLoadError": "无法加载备份",
|
||||
"UnableToLoadDevelopmentSettings": "无法加载开发设置",
|
||||
"DownloadClientsLoadError": "无法加载下载客户端",
|
||||
"UnableToLoadGeneralSettings": "无法加载通用设置",
|
||||
@@ -463,7 +463,7 @@
|
||||
"UnableToLoadUISettings": "无法加载UI设置",
|
||||
"UnsavedChanges": "未保存更改",
|
||||
"UnselectAll": "取消全选",
|
||||
"UpdateAutomaticallyHelpText": "自动下载并安装更新。你还可以在“系统:更新”中安装",
|
||||
"UpdateAutomaticallyHelpText": "自动下载并安装更新。您还可以在「“系统”->“更新”」中安装",
|
||||
"UpdateAvailableHealthCheckMessage": "有新的更新可用",
|
||||
"UpdateStartupNotWritableHealthCheckMessage": "无法安装更新,因为用户“{userName}”对于启动文件夹“{startupFolder}”没有写入权限。",
|
||||
"UpdateStartupTranslocationHealthCheckMessage": "无法安装更新,因为启动文件夹“{0}”在一个应用程序迁移文件夹。Cannot install update because startup folder '{startupFolder}' is in an App Translocation folder.",
|
||||
@@ -599,7 +599,7 @@
|
||||
"PackSeedTime": "做种时间",
|
||||
"PasswordConfirmation": "确认密码",
|
||||
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "确认新密码",
|
||||
"InvalidUILanguage": "您的UI设置为无效语言,请纠正并保存设置",
|
||||
"InvalidUILanguage": "您的 UI 设置为无效语言,请纠正并保存设置",
|
||||
"NoIndexerCategories": "没有找到此索引器的分类",
|
||||
"DownloadClientQbittorrentSettingsContentLayout": "内容布局",
|
||||
"DownloadClientQbittorrentSettingsContentLayoutHelpText": "是否使用 qBittorrent 配置的内容布局,使用种子的原始布局或始终创建子文件夹(qBittorrent 4.3.2+)",
|
||||
@@ -609,7 +609,7 @@
|
||||
"BlackholeFolderHelpText": "{appName} 将在其中存储 {extension} 文件的文件夹",
|
||||
"ApplicationSettingsSyncRejectBlocklistedTorrentHashes": "在抓取时不会同步黑名单种子",
|
||||
"UsenetBlackholeNzbFolder": "NZB文件夹",
|
||||
"DownloadClientFreeboxSettingsAppIdHelpText": "创建访问 Freebox API 所需的 App ID(即“app_id”)",
|
||||
"DownloadClientFreeboxSettingsAppIdHelpText": "创建访问 Freebox API 所需的 App ID(即 “app_id”)",
|
||||
"DownloadClientNzbgetSettingsAddPausedHelpText": "此选项至少需要 NzbGet 版本 16.0",
|
||||
"DownloadClientQbittorrentSettingsSequentialOrderHelpText": "按顺序下载文件(qBittorrent 4.1.0+)",
|
||||
"TorrentBlackholeSaveMagnetFilesHelpText": "如果没有可用的 .torrent 文件,请保存磁力链接(仅当下载客户端支持保存到文件的磁力连接时才有用)",
|
||||
@@ -619,7 +619,7 @@
|
||||
"DownloadClientDelugeSettingsUrlBaseHelpText": "向 Deluge JSON URL 添加前缀,请参阅 {url}",
|
||||
"DownloadClientFloodSettingsUrlBaseHelpText": "为 Flood API 添加前缀,例如 {url}",
|
||||
"DownloadClientFreeboxSettingsAppToken": "App Token",
|
||||
"DownloadClientFreeboxSettingsAppTokenHelpText": "创建访问 Freebox API 所需的 App token(即“ app_token”)",
|
||||
"DownloadClientFreeboxSettingsAppTokenHelpText": "创建访问 Freebox API 所需的 App token(即 “ app_token”)",
|
||||
"DownloadClientQbittorrentSettingsInitialStateHelpText": "添加到 qBittorrent 的种子的初始状态。 请注意,强制做种不遵守种子限制",
|
||||
"GrabRelease": "抓取版本",
|
||||
"ManualGrab": "手动抓取",
|
||||
@@ -641,7 +641,7 @@
|
||||
"ApplicationSettingsSyncRejectBlocklistedTorrentHashesHelpText": "如果 torrent 的哈希被屏蔽了,某些索引器在使用RSS或者搜索期间可能无法正确拒绝它,启用此功能将允许在抓取 torrent 之后但在将其发送到客户端之前拒绝它。",
|
||||
"DownloadClientDownloadStationSettingsDirectoryHelpText": "用于存放下载内容的共享文件夹可选择,留空使用默认的 Download Station 位置",
|
||||
"DownloadClientFloodSettingsAdditionalTagsHelpText": "添加媒体属性作为标签。 提示是示例。",
|
||||
"DownloadClientFreeboxSettingsApiUrlHelpText": "使用 API 版本定义 Freebox API 基本 URL,例如“{url}”,默认为“{defaultApiUrl}”",
|
||||
"DownloadClientFreeboxSettingsApiUrlHelpText": "使用 API 版本定义 Freebox API 基本 URL,例如 “{url}”,默认为 “{defaultApiUrl}”",
|
||||
"DownloadClientPneumaticSettingsStrmFolder": "Strm 文件夹",
|
||||
"DownloadClientQbittorrentSettingsFirstAndLastFirstHelpText": "首先下载第一个和最后一个片段(qBittorrent 4.1.0+)",
|
||||
"DownloadClientQbittorrentSettingsUseSslHelpText": "使用安全连接。 请参阅 qBittorrent 中的「选项 -> Web UI -> “使用 HTTPS 而不是 HTTP”」。",
|
||||
@@ -654,7 +654,7 @@
|
||||
"IndexerSettingsAppsMinimumSeeders": "应用程序最少种子数",
|
||||
"IndexerSettingsPackSeedTimeIndexerHelpText": "种子下载的时间(季或专辑)应在停止前保持上传状态,应用程序默认设定为empty",
|
||||
"IndexerHDBitsSettingsOriginsHelpText": "如果未指定,则使用所有选项。",
|
||||
"DownloadClientFreeboxSettingsHostHelpText": "Freebox 的主机名或主机 IP 地址,默认为“{url}”(仅在同一网络上有效)",
|
||||
"DownloadClientFreeboxSettingsHostHelpText": "Freebox 的主机名或主机 IP 地址,默认为 “{url}”(仅在同一网络上有效)",
|
||||
"DownloadClientFreeboxSettingsPortHelpText": "用于访问 Freebox 接口的端口,默认为 '{port}'",
|
||||
"DownloadClientQbittorrentSettingsFirstAndLastFirst": "先下载首尾文件块",
|
||||
"DownloadClientSettingsAddPaused": "添加并暂停",
|
||||
@@ -670,7 +670,7 @@
|
||||
"Menu": "菜单",
|
||||
"Mixed": "混合",
|
||||
"TorrentBlackholeSaveMagnetFilesExtension": "保存磁力链接文件扩展名",
|
||||
"TorrentBlackholeSaveMagnetFilesExtensionHelpText": "用于磁力链接的扩展名,默认为“.magnet”",
|
||||
"TorrentBlackholeSaveMagnetFilesExtensionHelpText": "用于磁力链接的扩展名,默认为 “.magnet”",
|
||||
"Destination": "目标",
|
||||
"Directory": "目录",
|
||||
"IndexerHDBitsSettingsCodecs": "编解码器",
|
||||
@@ -711,5 +711,24 @@
|
||||
"AverageGrabs": "平均抓取次数",
|
||||
"AverageQueries": "平均查询次数",
|
||||
"DefaultCategory": "默认分类",
|
||||
"DownloadClientSettingsDefaultCategorySubFolderHelpText": "默认的备用分类,当发布资源没有匹配的分类时将使用此分类。为 {appName} 添加一个特定的分类,可以避免与非 {appName} 的无关下载发生冲突。分类是可选的,但强烈建议使用。启用分类后,会在输出目录中创建一个 [分类] 子目录。"
|
||||
"DownloadClientSettingsDefaultCategorySubFolderHelpText": "默认的备用分类,当发布资源没有匹配的分类时将使用此分类。为 {appName} 添加一个特定的分类,可以避免与非 {appName} 的无关下载发生冲突。分类是可选的,但强烈建议使用。启用分类后,会在输出目录中创建一个 [分类] 子目录。",
|
||||
"ErrorRestoringBackup": "恢复备份错误",
|
||||
"UpdaterLogFiles": "更新器日志文件",
|
||||
"WouldYouLikeToRestoreBackup": "是否要还原备份 “{name}”?",
|
||||
"AptUpdater": "使用apt安装更新",
|
||||
"DockerUpdater": "更新Docker容器以更新应用",
|
||||
"Download": "下载",
|
||||
"ExternalUpdater": "{appName}配置为使用外部更新机制",
|
||||
"FailedToFetchUpdates": "获取更新失败",
|
||||
"LogFilesLocation": "日志文件位于: {location}",
|
||||
"Logout": "注销",
|
||||
"NoEventsFound": "无事件",
|
||||
"RestartReloadNote": "注意:{appName}将在恢复过程中自动重启并重新加载UI。",
|
||||
"TheLogLevelDefault": "默认的日志等级为 \"Info\",可以在 [常规设置] 中修改 (/settings/general)",
|
||||
"UpdateAppDirectlyLoadError": "无法直接更新{appName},",
|
||||
"InstallLatest": "安装最新版",
|
||||
"Install": "安装",
|
||||
"InstallMajorVersionUpdate": "安装更新",
|
||||
"InstallMajorVersionUpdateMessage": "此更新将安装新的主要版本,这可能与您的系统不兼容。您确定要安装此更新吗?",
|
||||
"InstallMajorVersionUpdateMessageLink": "请查看 [{domain}]({url}) 以获取更多信息。"
|
||||
}
|
||||
|
||||
@@ -135,5 +135,7 @@
|
||||
"IndexerHDBitsSettingsCodecs": "編解碼器",
|
||||
"Directory": "目錄",
|
||||
"BuiltIn": "內建的",
|
||||
"AllSearchResultsHiddenByFilter": "根據所使用的篩選器已將所有結果隱藏"
|
||||
"AllSearchResultsHiddenByFilter": "根據所使用的篩選器已將所有結果隱藏",
|
||||
"AptUpdater": "使用apt安裝更新",
|
||||
"Discord": "Discord"
|
||||
}
|
||||
|
||||
@@ -105,6 +105,8 @@ namespace NzbDrone.Core.Messaging.Commands
|
||||
_logger.Trace("Publishing {0}", command.Name);
|
||||
_logger.Trace("Checking if command is queued or started: {0}", command.Name);
|
||||
|
||||
command.Trigger = trigger;
|
||||
|
||||
lock (_commandQueue)
|
||||
{
|
||||
var existingCommands = QueuedOrStarted(command.Name);
|
||||
@@ -141,7 +143,6 @@ namespace NzbDrone.Core.Messaging.Commands
|
||||
var command = GetCommand(commandName);
|
||||
command.LastExecutionTime = lastExecutionTime;
|
||||
command.LastStartTime = lastStartTime;
|
||||
command.Trigger = trigger;
|
||||
|
||||
return Push(command, priority, trigger);
|
||||
}
|
||||
@@ -232,13 +233,13 @@ namespace NzbDrone.Core.Messaging.Commands
|
||||
_repo.Trim();
|
||||
}
|
||||
|
||||
private dynamic GetCommand(string commandName)
|
||||
private Command GetCommand(string commandName)
|
||||
{
|
||||
commandName = commandName.Split('.').Last();
|
||||
var commands = _knownTypes.GetImplementations(typeof(Command));
|
||||
var commandType = commands.Single(c => c.Name.Equals(commandName, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
return Json.Deserialize("{}", commandType);
|
||||
return Json.Deserialize("{}", commandType) as Command;
|
||||
}
|
||||
|
||||
private void Update(CommandModel command, CommandStatus status, string message)
|
||||
|
||||
@@ -2,10 +2,12 @@ using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Core.Update.Commands
|
||||
{
|
||||
public class ApplicationCheckUpdateCommand : Command
|
||||
public class ApplicationUpdateCheckCommand : Command
|
||||
{
|
||||
public override bool SendUpdatesToClient => true;
|
||||
|
||||
public override string CompletionMessage => null;
|
||||
|
||||
public bool InstallMajorUpdate { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace NzbDrone.Core.Update.Commands
|
||||
{
|
||||
public class ApplicationUpdateCommand : Command
|
||||
{
|
||||
public bool InstallMajorUpdate { get; set; }
|
||||
public override bool SendUpdatesToClient => true;
|
||||
public override bool IsExclusive => true;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ using NzbDrone.Core.Update.Commands;
|
||||
|
||||
namespace NzbDrone.Core.Update
|
||||
{
|
||||
public class InstallUpdateService : IExecute<ApplicationCheckUpdateCommand>, IExecute<ApplicationUpdateCommand>, IHandle<ApplicationStartingEvent>
|
||||
public class InstallUpdateService : IExecute<ApplicationUpdateCommand>, IExecute<ApplicationUpdateCheckCommand>, IHandle<ApplicationStartingEvent>
|
||||
{
|
||||
private readonly ICheckUpdateService _checkUpdateService;
|
||||
private readonly Logger _logger;
|
||||
@@ -231,7 +231,7 @@ namespace NzbDrone.Core.Update
|
||||
}
|
||||
}
|
||||
|
||||
private UpdatePackage GetUpdatePackage(CommandTrigger updateTrigger)
|
||||
private UpdatePackage GetUpdatePackage(CommandTrigger updateTrigger, bool installMajorUpdate)
|
||||
{
|
||||
_logger.ProgressDebug("Checking for updates");
|
||||
|
||||
@@ -243,18 +243,24 @@ namespace NzbDrone.Core.Update
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_osInfo.IsDocker)
|
||||
if (latestAvailable.Version.Major > BuildInfo.Version.Major && !installMajorUpdate)
|
||||
{
|
||||
_logger.ProgressDebug("Updating is disabled inside a docker container. Please update the container image.");
|
||||
_logger.ProgressInfo("Unable to install major update, please update update manually from System: Updates");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (OsInfo.IsNotWindows && !_configFileProvider.UpdateAutomatically && updateTrigger != CommandTrigger.Manual)
|
||||
if (!_configFileProvider.UpdateAutomatically && updateTrigger != CommandTrigger.Manual)
|
||||
{
|
||||
_logger.ProgressDebug("Auto-update not enabled, not installing available update.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_configFileProvider.UpdateMechanism == UpdateMechanism.BuiltIn && _deploymentInfoProvider.PackageUpdateMechanism == UpdateMechanism.Docker)
|
||||
{
|
||||
_logger.ProgressDebug("Built-In updater disabled inside a docker container. Please update the container image.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Safety net, ConfigureUpdateMechanism should take care of invalid settings
|
||||
if (_configFileProvider.UpdateMechanism == UpdateMechanism.BuiltIn && _deploymentInfoProvider.IsExternalUpdateMechanism)
|
||||
{
|
||||
@@ -270,9 +276,9 @@ namespace NzbDrone.Core.Update
|
||||
return latestAvailable;
|
||||
}
|
||||
|
||||
public void Execute(ApplicationCheckUpdateCommand message)
|
||||
public void Execute(ApplicationUpdateCheckCommand message)
|
||||
{
|
||||
if (GetUpdatePackage(message.Trigger) != null)
|
||||
if (GetUpdatePackage(message.Trigger, true) != null)
|
||||
{
|
||||
_commandQueueManager.Push(new ApplicationUpdateCommand(), trigger: message.Trigger);
|
||||
}
|
||||
@@ -280,7 +286,7 @@ namespace NzbDrone.Core.Update
|
||||
|
||||
public void Execute(ApplicationUpdateCommand message)
|
||||
{
|
||||
var latestAvailable = GetUpdatePackage(message.Trigger);
|
||||
var latestAvailable = GetUpdatePackage(message.Trigger, message.InstallMajorUpdate);
|
||||
|
||||
if (latestAvailable != null)
|
||||
{
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace NzbDrone.Core.Update
|
||||
.AddQueryParam("runtime", "netcore")
|
||||
.AddQueryParam("runtimeVer", _platformInfo.Version)
|
||||
.AddQueryParam("dbType", _mainDatabase.DatabaseType)
|
||||
.AddQueryParam("includeMajorVersion", true)
|
||||
.SetSegment("branch", branch);
|
||||
|
||||
if (_analyticsService.IsEnabled)
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace NzbDrone.Integration.Test.ApiTests
|
||||
[Test]
|
||||
public void should_be_able_to_run_update_check()
|
||||
{
|
||||
var response = Commands.Post(new SimpleCommandResource { Name = "applicationcheckupdate" });
|
||||
var response = Commands.Post(new SimpleCommandResource { Name = "applicationupdatecheck" });
|
||||
|
||||
response.Id.Should().NotBe(0);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using NzbDrone.Core.Applications;
|
||||
using NzbDrone.SignalR;
|
||||
using Prowlarr.Http;
|
||||
|
||||
namespace Prowlarr.Api.V1.Applications
|
||||
@@ -9,8 +10,8 @@ namespace Prowlarr.Api.V1.Applications
|
||||
public static readonly ApplicationResourceMapper ResourceMapper = new ();
|
||||
public static readonly ApplicationBulkResourceMapper BulkResourceMapper = new ();
|
||||
|
||||
public ApplicationController(ApplicationFactory applicationsFactory)
|
||||
: base(applicationsFactory, "applications", ResourceMapper, BulkResourceMapper)
|
||||
public ApplicationController(IBroadcastSignalRMessage signalRBroadcaster, ApplicationFactory applicationsFactory)
|
||||
: base(signalRBroadcaster, applicationsFactory, "applications", ResourceMapper, BulkResourceMapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,9 +61,8 @@ namespace Prowlarr.Api.V1.Commands
|
||||
using var reader = new StreamReader(Request.Body);
|
||||
var body = reader.ReadToEnd();
|
||||
|
||||
dynamic command = STJson.Deserialize(body, commandType);
|
||||
var command = STJson.Deserialize(body, commandType) as Command;
|
||||
|
||||
command.Trigger = CommandTrigger.Manual;
|
||||
command.SuppressMessages = !command.SendUpdatesToClient;
|
||||
command.SendUpdatesToClient = true;
|
||||
command.ClientUserAgent = Request.Headers["User-Agent"];
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.SignalR;
|
||||
using Prowlarr.Http;
|
||||
|
||||
namespace Prowlarr.Api.V1.DownloadClient
|
||||
@@ -9,8 +10,8 @@ namespace Prowlarr.Api.V1.DownloadClient
|
||||
public static readonly DownloadClientResourceMapper ResourceMapper = new ();
|
||||
public static readonly DownloadClientBulkResourceMapper BulkResourceMapper = new ();
|
||||
|
||||
public DownloadClientController(IDownloadClientFactory downloadClientFactory)
|
||||
: base(downloadClientFactory, "downloadclient", ResourceMapper, BulkResourceMapper)
|
||||
public DownloadClientController(IBroadcastSignalRMessage signalRBroadcaster, IDownloadClientFactory downloadClientFactory)
|
||||
: base(signalRBroadcaster, downloadClientFactory, "downloadclient", ResourceMapper, BulkResourceMapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NzbDrone.Core.IndexerProxies;
|
||||
using NzbDrone.SignalR;
|
||||
using Prowlarr.Http;
|
||||
|
||||
namespace Prowlarr.Api.V1.IndexerProxies
|
||||
@@ -11,8 +12,8 @@ namespace Prowlarr.Api.V1.IndexerProxies
|
||||
public static readonly IndexerProxyResourceMapper ResourceMapper = new ();
|
||||
public static readonly IndexerProxyBulkResourceMapper BulkResourceMapper = new ();
|
||||
|
||||
public IndexerProxyController(IndexerProxyFactory notificationFactory)
|
||||
: base(notificationFactory, "indexerProxy", ResourceMapper, BulkResourceMapper)
|
||||
public IndexerProxyController(IBroadcastSignalRMessage signalRBroadcaster, IndexerProxyFactory notificationFactory)
|
||||
: base(signalRBroadcaster, notificationFactory, "indexerProxy", ResourceMapper, BulkResourceMapper)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Validation;
|
||||
using NzbDrone.SignalR;
|
||||
using Prowlarr.Http;
|
||||
|
||||
namespace Prowlarr.Api.V1.Indexers
|
||||
@@ -8,12 +9,13 @@ namespace Prowlarr.Api.V1.Indexers
|
||||
[V1ApiController]
|
||||
public class IndexerController : ProviderControllerBase<IndexerResource, IndexerBulkResource, IIndexer, IndexerDefinition>
|
||||
{
|
||||
public IndexerController(IndexerFactory indexerFactory,
|
||||
public IndexerController(IBroadcastSignalRMessage signalRBroadcaster,
|
||||
IndexerFactory indexerFactory,
|
||||
IndexerResourceMapper resourceMapper,
|
||||
IndexerBulkResourceMapper bulkResourceMapper,
|
||||
AppProfileExistsValidator appProfileExistsValidator,
|
||||
DownloadClientExistsValidator downloadClientExistsValidator)
|
||||
: base(indexerFactory, "indexer", resourceMapper, bulkResourceMapper)
|
||||
: base(signalRBroadcaster, indexerFactory, "indexer", resourceMapper, bulkResourceMapper)
|
||||
{
|
||||
SharedValidator.RuleFor(c => c.AppProfileId).Cascade(CascadeMode.Stop)
|
||||
.ValidId()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NzbDrone.Core.Notifications;
|
||||
using NzbDrone.SignalR;
|
||||
using Prowlarr.Http;
|
||||
|
||||
namespace Prowlarr.Api.V1.Notifications
|
||||
@@ -11,8 +12,8 @@ namespace Prowlarr.Api.V1.Notifications
|
||||
public static readonly NotificationResourceMapper ResourceMapper = new ();
|
||||
public static readonly NotificationBulkResourceMapper BulkResourceMapper = new ();
|
||||
|
||||
public NotificationController(NotificationFactory notificationFactory)
|
||||
: base(notificationFactory, "notification", ResourceMapper, BulkResourceMapper)
|
||||
public NotificationController(IBroadcastSignalRMessage signalRBroadcaster, NotificationFactory notificationFactory)
|
||||
: base(signalRBroadcaster, notificationFactory, "notification", ResourceMapper, BulkResourceMapper)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,21 @@ using FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.ThingiProvider.Events;
|
||||
using NzbDrone.Core.Validation;
|
||||
using NzbDrone.Http.REST.Attributes;
|
||||
using NzbDrone.SignalR;
|
||||
using Prowlarr.Http.REST;
|
||||
|
||||
namespace Prowlarr.Api.V1
|
||||
{
|
||||
public abstract class ProviderControllerBase<TProviderResource, TBulkProviderResource, TProvider, TProviderDefinition> : RestController<TProviderResource>
|
||||
public abstract class ProviderControllerBase<TProviderResource, TBulkProviderResource, TProvider, TProviderDefinition> : RestControllerWithSignalR<TProviderResource, TProviderDefinition>,
|
||||
IHandle<ProviderAddedEvent<TProvider>>,
|
||||
IHandle<ProviderUpdatedEvent<TProvider>>,
|
||||
IHandle<ProviderDeletedEvent<TProvider>>
|
||||
where TProviderDefinition : ProviderDefinition, new()
|
||||
where TBulkProviderResource : ProviderBulkResource<TBulkProviderResource>, new()
|
||||
where TProvider : IProvider
|
||||
@@ -21,11 +28,13 @@ namespace Prowlarr.Api.V1
|
||||
protected readonly ProviderResourceMapper<TProviderResource, TProviderDefinition> _resourceMapper;
|
||||
private readonly ProviderBulkResourceMapper<TBulkProviderResource, TProviderDefinition> _bulkResourceMapper;
|
||||
|
||||
protected ProviderControllerBase(IProviderFactory<TProvider,
|
||||
protected ProviderControllerBase(IBroadcastSignalRMessage signalRBroadcaster,
|
||||
IProviderFactory<TProvider,
|
||||
TProviderDefinition> providerFactory,
|
||||
string resource,
|
||||
ProviderResourceMapper<TProviderResource, TProviderDefinition> resourceMapper,
|
||||
ProviderBulkResourceMapper<TBulkProviderResource, TProviderDefinition> bulkResourceMapper)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_providerFactory = providerFactory;
|
||||
_resourceMapper = resourceMapper;
|
||||
@@ -244,6 +253,24 @@ namespace Prowlarr.Api.V1
|
||||
return Json(data);
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public void Handle(ProviderAddedEvent<TProvider> message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Created, message.Definition.Id);
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public void Handle(ProviderUpdatedEvent<TProvider> message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, message.Definition.Id);
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public void Handle(ProviderDeletedEvent<TProvider> message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Deleted, message.ProviderId);
|
||||
}
|
||||
|
||||
private void Validate(TProviderDefinition definition, bool includeWarnings)
|
||||
{
|
||||
var validationResult = definition.Settings.Validate();
|
||||
|
||||
Reference in New Issue
Block a user